declare namespace RPGMakerMV {
    type ActorIteratorCallback = (actor: DataActor, index?: number, partyMembers?: DataActor[]) => void
    type EnemyIteratorCallback = (actor: DataEnemy, index?: number, troopMembers?: DataEnemy[]) => void

    type DefaultLetterTableHalf = [
        ' A',' B',' C',' D',' E',' F',' G',' H',' I',' J',' K',' L',' M',
        ' N',' O',' P',' Q',' R',' S',' T',' U',' V',' W',' X',' Y',' Z'
    ]
    type DefaultLetterTableFull = [
        'Ａ','Ｂ','Ｃ','Ｄ','Ｅ','Ｆ','Ｇ','Ｈ','Ｉ','Ｊ','Ｋ','Ｌ','Ｍ',
        'Ｎ','Ｏ','Ｐ','Ｑ','Ｒ','Ｓ','Ｔ','Ｕ','Ｖ','Ｗ','Ｘ','Ｙ','Ｚ'
    ]

    interface BattlerAnimation {
        animationId: string;
        mirror: boolean;
        delay: number;
    }
}

//=============================================================================
// rpg_objects.js v1.6.2
//=============================================================================

//-----------------------------------------------------------------------------
// Game_Temp
//
// The game object class for temporary data that is not included in save data.

class Game_Temp {
    constructor() {
        this.initialize.apply(this, arguments);
    }

    initialize(): void {
        this._isPlaytest = Utils.isOptionValid('test');
        this._commonEventId = 0;
        this._destinationX = null;
        this._destinationY = null;
    };

    isPlaytest(): boolean {
        return this._isPlaytest;
    };

    reserveCommonEvent(commonEventId: number): void {
        this._commonEventId = commonEventId;
    };

    clearCommonEvent(): void {
        this._commonEventId = 0;
    };

    isCommonEventReserved(): boolean {
        return this._commonEventId > 0;
    };

    reservedCommonEvent(): RPGMakerMV.DataCommonEvent {
        return $dataCommonEvents[this._commonEventId];
    };

    setDestination(x: number, y: number): void {
        this._destinationX = x;
        this._destinationY = y;
    };

    clearDestination(): void {
        this._destinationX = null;
        this._destinationY = null;
    };

    isDestinationValid(): boolean {
        return this._destinationX !== null;
    };

    destinationX(): number {
        return this._destinationX;
    };

    destinationY(): number {
        return this._destinationY;
    };

    _isPlaytest: boolean|any;
    _commonEventId: number;
    _destinationX: number;
    _destinationY: number;
}

//-----------------------------------------------------------------------------
// Game_System
//
// The game object class for the system data.

class Game_System {
    constructor() {
        this.initialize.apply(this, arguments);
    }
    initialize(): void {
        this._saveEnabled = true;
        this._menuEnabled = true;
        this._encounterEnabled = true;
        this._formationEnabled = true;
        this._battleCount = 0;
        this._winCount = 0;
        this._escapeCount = 0;
        this._saveCount = 0;
        this._versionId = 0;
        this._framesOnSave = 0;
        this._bgmOnSave = null;
        this._bgsOnSave = null;
        this._windowTone = null;
        this._battleBgm = null;
        this._victoryMe = null;
        this._defeatMe = null;
        this._savedBgm = null;
        this._walkingBgm = null;
    };
   
    isJapanese(): boolean {
        return $dataSystem.locale.match(/^ja/);
    };

    isChinese(): boolean {
        return $dataSystem.locale.match(/^zh/);
    };

    isKorean(): boolean {
        return $dataSystem.locale.match(/^ko/);
    };

    isCJK(): boolean {
        return $dataSystem.locale.match(/^(ja|zh|ko)/);
    };

    isRussian(): boolean {
        return $dataSystem.locale.match(/^ru/);
    };

    isSideView(): boolean{
        return $dataSystem.optSideView;
    };

    isSaveEnabled(): boolean {
        return this._saveEnabled;
    };

    disableSave(): void {
        this._saveEnabled = false;
    };

    enableSave(): void {
        this._saveEnabled = true;
    };

    isMenuEnabled(): boolean {
        return this._menuEnabled;
    };

    disableMenu(): void {
        this._menuEnabled = false;
    };

    enableMenu(): void {
        this._menuEnabled = true;
    };

    isEncounterEnabled(): boolean {
        return this._encounterEnabled;
    };

    disableEncounter(): void {
        this._encounterEnabled = false;
    };

    enableEncounter(): void {
        this._encounterEnabled = true;
    };

    isFormationEnabled(): boolean {
        return this._formationEnabled;
    };

    disableFormation(): void {
        this._formationEnabled = false;
    };

    enableFormation(): void {
        this._formationEnabled = true;
    };

    battleCount(): number {
        return this._battleCount;
    };

    winCount(): number {
        return this._winCount;
    };

    escapeCount(): number {
        return this._escapeCount;
    };

    saveCount(): number {
        return this._saveCount;
    };

    versionId(): number {
        return this._versionId;
    };

    windowTone(): number[] {
        return this._windowTone || $dataSystem.windowTone;
    };

    setWindowTone(value: number[]): void {
        this._windowTone = value;
    };

    battleBgm(): RPGMakerMV.Sound {
        return this._battleBgm || $dataSystem.battleBgm;
    };

    setBattleBgm(value: RPGMakerMV.Sound): void {
        this._battleBgm = value;
    };

    victoryMe(): RPGMakerMV.Sound {
        return this._victoryMe || $dataSystem.victoryMe;
    };

    setVictoryMe(value: RPGMakerMV.Sound): void {
        this._victoryMe = value;
    };

    defeatMe(): RPGMakerMV.Sound {
        return this._defeatMe || $dataSystem.defeatMe;
    };

    setDefeatMe(value: RPGMakerMV.Sound): void {
        this._defeatMe = value;
    };

    onBattleStart(): void {
        this._battleCount++;
    };

    onBattleWin(): void {
        this._winCount++;
    };

    onBattleEscape(): void {
        this._escapeCount++;
    };

    onBeforeSave(): void {
        this._saveCount++;
        this._versionId = $dataSystem.versionId;
        this._framesOnSave = Graphics.frameCount;
        this._bgmOnSave = AudioManager.saveBgm();
        this._bgsOnSave = AudioManager.saveBgs();
    };

    onAfterLoad(): void {
        Graphics.frameCount = this._framesOnSave;
        AudioManager.playBgm(this._bgmOnSave);
        AudioManager.playBgs(this._bgsOnSave);
    };

    playtime(): number {
        return Math.floor(Graphics.frameCount / 60);
    };

    playtimeText(): string {
        var hour = Math.floor(this.playtime() / 60 / 60);
        var min = Math.floor(this.playtime() / 60) % 60;
        var sec = this.playtime() % 60;
        return hour.padZero(2) + ':' + min.padZero(2) + ':' + sec.padZero(2);
    };

    saveBgm(): void {
        this._savedBgm = AudioManager.saveBgm();
    };

    replayBgm(): void {
        if (this._savedBgm) {
            AudioManager.replayBgm(this._savedBgm);
        }
    };

    saveWalkingBgm(): void {
        this._walkingBgm = AudioManager.saveBgm();
    };

    replayWalkingBgm(): void {
        if (this._walkingBgm) {
            AudioManager.playBgm(this._walkingBgm);
        }
    };

    saveWalkingBgm2(): void {
        this._walkingBgm = $dataMap.bgm;
    };

    _saveEnabled: boolean;
    _menuEnabled: boolean;
    _encounterEnabled: boolean;
    _formationEnabled: boolean;
    _battleCount: number;
    _winCount: number;
    _escapeCount: number;
    _saveCount: number;
    _versionId: number;
    _framesOnSave: number;
    _bgmOnSave: RPGMakerMV.AudioObject;
    _bgsOnSave: RPGMakerMV.AudioObject;
    _windowTone: number[];
    _battleBgm: RPGMakerMV.Sound;
    _victoryMe: RPGMakerMV.Sound;
    _defeatMe: RPGMakerMV.Sound;
    _savedBgm: RPGMakerMV.Sound;
    _walkingBgm: RPGMakerMV.Sound;
}

//-----------------------------------------------------------------------------
// Game_Timer
//
// The game object class for the timer.

class Game_Timer {
    constructor() {
        this.initialize.apply(this, arguments);
    }

    initialize(): void {
        this._frames = 0;
        this._working = false;
    };

    update(sceneActive: boolean): void {
        if (sceneActive && this._working && this._frames > 0) {
            this._frames--;
            if (this._frames === 0) {
                this.onExpire();
            }
        }
    };

    start(count: number): void {
        this._frames = count;
        this._working = true;
    };

    stop(): void {
        this._working = false;
    };

    isWorking(): boolean {
        return this._working;
    };

    seconds(): number {
        return Math.floor(this._frames / 60);
    };

    onExpire(): void {
        BattleManager.abort();
    };

    _frames: number;
    _working: boolean;
}

//-----------------------------------------------------------------------------
// Game_Message
//
// The game object class for the state of the message window that displays text
// or selections, etc.

class Game_Message {
    constructor() {
        this.initialize.apply(this, arguments);
    }

    initialize(): void {
        this.clear();
    };

    clear(): void {
        this._texts = [];
        this._choices = [];
        this._faceName = '';
        this._faceIndex = 0;
        this._background = 0;
        this._positionType = 2;
        this._choiceDefaultType = 0;
        this._choiceCancelType = 0;
        this._choiceBackground = 0;
        this._choicePositionType = 2;
        this._numInputVariableId = 0;
        this._numInputMaxDigits = 0;
        this._itemChoiceVariableId = 0;
        this._itemChoiceItypeId = 0;
        this._scrollMode = false;
        this._scrollSpeed = 2;
        this._scrollNoFast = false;
        this._choiceCallback = null;
    };


    choices(): string[] {
        return this._choices;
    };

    faceName(): string {
        return this._faceName;
    };

    faceIndex(): number {
        return this._faceIndex;
    };

    background(): number {
        return this._background;
    };

    positionType(): number {
        return this._positionType;
    };

    choiceDefaultType(): number {
        return this._choiceDefaultType;
    };

    choiceCancelType(): number {
        return this._choiceCancelType;
    };

    choiceBackground(): number {
        return this._choiceBackground;
    };

    choicePositionType(): number {
        return this._choicePositionType;
    };

    numInputVariableId(): number {
        return this._numInputVariableId;
    };

    numInputMaxDigits(): number {
        return this._numInputMaxDigits;
    };

    itemChoiceVariableId(): number {
        return this._itemChoiceVariableId;
    };

    itemChoiceItypeId(): number {
        return this._itemChoiceItypeId;
    };

    scrollMode(): boolean {
        return this._scrollMode;
    };

    scrollSpeed(): number {
        return this._scrollSpeed;
    };

    scrollNoFast(): boolean {
        return this._scrollNoFast;
    };

    add(text: string): void {
        this._texts.push(text);
    };

    setFaceImage(faceName: string, faceIndex: number): void {
        this._faceName = faceName;
        this._faceIndex = faceIndex;
    };

    setBackground(background: number): void {
        this._background = background;
    };

    setPositionType(positionType: number): void {
        this._positionType = positionType;
    };

    setChoices(choices: string[], defaultType: number, cancelType: number): void {
        this._choices = choices;
        this._choiceDefaultType = defaultType;
        this._choiceCancelType = cancelType;
    };

    setChoiceBackground(background: number): void {
        this._choiceBackground = background;
    };
    
    setChoicePositionType(positionType: number): void {
        this._choicePositionType = positionType;
    };

    setNumberInput(variableId: number, maxDigits: number): void {
        this._numInputVariableId = variableId;
        this._numInputMaxDigits = maxDigits;
    };

    setItemChoice(variableId: number, itemType: number): void {
        this._itemChoiceVariableId = variableId;
        this._itemChoiceItypeId = itemType;
    };

    setScroll(speed: number, noFast: boolean): void {
        this._scrollMode = true;
        this._scrollSpeed = speed;
        this._scrollNoFast = noFast;
    };

    setChoiceCallback(callback: Function): void {
        this._choiceCallback = callback;
    };

    onChoice(n: number): void {
        if (this._choiceCallback) {
            this._choiceCallback(n);
            this._choiceCallback = null;
        }
    };

    hasText(): boolean {
        return this._texts.length > 0;
    };

    isChoice(): boolean {
        return this._choices.length > 0;
    };

    isNumberInput(): boolean {
        return this._numInputVariableId > 0;
    };

    isItemChoice(): boolean {
        return this._itemChoiceVariableId > 0;
    };

    isBusy(): boolean {
        return (this.hasText() || this.isChoice() ||
                this.isNumberInput() || this.isItemChoice());
    };

    newPage(): void {
        if (this._texts.length > 0) {
            this._texts[this._texts.length - 1] += '\f';
        }
    };

    allText(): string {
        return this._texts.join('\n');
    };

        
    _texts: string[];
    _choices: string[];
    _faceName: string;
    _faceIndex: number;
    _background: number;
    _positionType: number;
    _choiceDefaultType: number;
    _choiceCancelType: number;
    _choiceBackground: number;
    _choicePositionType: number;
    _numInputVariableId: number;
    _numInputMaxDigits: number;
    _itemChoiceVariableId: number;
    _itemChoiceItypeId: number;
    _scrollMode: boolean;
    _scrollSpeed: number;
    _scrollNoFast: boolean;
    _choiceCallback: Function;
}

//-----------------------------------------------------------------------------
// Game_Switches
//
// The game object class for switches.

class Game_Switches {
    constructor() {
        this.initialize.apply(this, arguments);
    }

    initialize(): void {
        this.clear();
    };

    clear(): void {
        this._data = [];
    };
    
    value(switchId: number): boolean {
        return !!this._data[switchId];
    };
    
    setValue(switchId: number, value: boolean): void {
        if (switchId > 0 && switchId < $dataSystem.switches.length) {
            this._data[switchId] = value;
            this.onChange();
        }
    };

    onChange(): void {
        $gameMap.requestRefresh();
    };

    _data: boolean[];
}

//-----------------------------------------------------------------------------
// Game_Variables
//
// The game object class for variables.

class Game_Variables {
    constructor() {
        this.initialize.apply(this, arguments);
    }

    initialize(): void {
        this.clear();
    };

    clear(): void {
        this._data = [];
    };

    value(variableId: number): number {
        return this._data[variableId] || 0;
    };

    setValue(variableId: number, value: number): any {
        if (variableId > 0 && variableId < $dataSystem.variables.length) {
            if (typeof value === 'number') {
                value = Math.floor(value);
            }
            this._data[variableId] = value;
            this.onChange();
        }
    };

    onChange(): void {
        $gameMap.requestRefresh();
    };

    _data: number[];
}

//-----------------------------------------------------------------------------
// Game_SelfSwitches
//
// The game object class for self switches.

class Game_SelfSwitches {
    constructor() {
        this.initialize.apply(this, arguments);
    }

    initialize(): void {
        this.clear();
    };

    clear(): void {
        this._data = {};
    };

    value(key: number[]|any): boolean {
        return !!this._data[key];
    };

    setValue(key: Array<number | string> |any, value: boolean): void {
        if (value) {
            this._data[key] = true;
        } else {
            delete this._data[key];
        }
        this.onChange();
    };

    onChange(): void {
        $gameMap.requestRefresh();
    };

    _data: { [key: string]: boolean };
}

//-----------------------------------------------------------------------------
// Game_Screen
//
// The game object class for screen effect data, such as changes in color tone
// and flashes.

class Game_Screen {
    constructor() {
        this.initialize.apply(this, arguments);
    }

    initialize(): void {
        this.clear();
    };

    clear(): void {
        this.clearFade();
        this.clearTone();
        this.clearFlash();
        this.clearShake();
        this.clearZoom();
        this.clearWeather();
        this.clearPictures();
    };

    onBattleStart(): void {
        this.clearFade();
        this.clearFlash();
        this.clearShake();
        this.clearZoom();
        this.eraseBattlePictures();
    };
    
    brightness(): number {
        return this._brightness;
    };

    _brightness: number;
    tone(): number[] {
        return this._tone;
    };

    _tone: number[];
    flashColor(): number[] {
        return this._flashColor;
    };

    _flashColor: number[]|any;
    shake(): number {
        return this._shake;
    };

    _shake: number;
    zoomX(): number {
        return this._zoomX;
    };

    _zoomX: number;
    zoomY(): number {
        return this._zoomY;
    };

    _zoomY: number;
    zoomScale(): number {
        return this._zoomScale;
    };

    _zoomScale: number;
    weatherType(): string {
        return this._weatherType;
    };

    _weatherType: string;
    weatherPower(): number {
        return this._weatherPower;
    };
    _weatherPower: number;
    picture(pictureId: number): Game_Picture {
        var realPictureId = this.realPictureId(pictureId);
        return this._pictures[realPictureId];
    };

    _pictures: Game_Picture[];
    realPictureId(pictureId: number): number {
        if ($gameParty.inBattle()) {
            return pictureId + this.maxPictures();
        } else {
            return pictureId;
        }
    };

    clearFade(): void {
        this._brightness = 255;
        this._fadeOutDuration = 0;
        this._fadeInDuration = 0;
    };

    _fadeOutDuration: number;
    _fadeInDuration: number;
    clearTone(): void {
        this._tone = [0, 0, 0, 0];
        this._toneTarget = [0, 0, 0, 0];
        this._toneDuration = 0;
    };

    _toneTarget: number[]|any;
    _toneDuration: number;
    clearFlash(): void {
        this._flashColor = [0, 0, 0, 0];
        this._flashDuration = 0;
    };

    _flashDuration: number;
    _shakeDirection: number;
    clearShake(): void {
        this._shakePower = 0;
        this._shakeSpeed = 0;
        this._shakeDuration = 0;
        this._shakeDirection = 1;
        this._shake = 0;
    };

    _shakePower: number;
    _shakeSpeed: number;
    _shakeDuration: number;
    clearZoom(): void {
        this._zoomX = 0;
        this._zoomY = 0;
        this._zoomScale = 1;
        this._zoomScaleTarget = 1;
        this._zoomDuration = 0;
    };

    _zoomScaleTarget: number;
    _zoomDuration: number;
    clearWeather(): void {
        this._weatherType = 'none';
        this._weatherPower = 0;
        this._weatherPowerTarget = 0;
        this._weatherDuration = 0;
    };

    _weatherPowerTarget: number;
    _weatherDuration: number;
    clearPictures(): void {
        this._pictures = [];
    };

    eraseBattlePictures(): void {
        this._pictures = this._pictures.slice(0, this.maxPictures() + 1);
    };

    maxPictures(): number {
        return 100;
    };

    startFadeOut(duration: number): void {
        this._fadeOutDuration = duration;
        this._fadeInDuration = 0;
    };

    startFadeIn(duration: number): void {
        this._fadeInDuration = duration;
        this._fadeOutDuration = 0;
    };

    startTint(tone: number[], duration: number): void {
        this._toneTarget = tone.clone();
        this._toneDuration = duration;
        if (this._toneDuration === 0) {
            this._tone = this._toneTarget.clone();
        }
    };

    startFlash(color: number[], duration: number): void {
        this._flashColor = color.clone();
        this._flashDuration = duration;
    };

    startShake(power: number, speed: number, duration: number): void {
        this._shakePower = power;
        this._shakeSpeed = speed;
        this._shakeDuration = duration;
    };

    startZoom(x: number, y: number, scale: number, duration: number): void {
        this._zoomX = x;
        this._zoomY = y;
        this._zoomScaleTarget = scale;
        this._zoomDuration = duration;
    };

    setZoom(x: number, y: number, scale: number): void {
        this._zoomX = x;
        this._zoomY = y;
        this._zoomScale = scale;
    };

    changeWeather(type: string, power: number, duration: number): void {
        if (type !== 'none' || duration === 0) {
            this._weatherType = type;
        }
        this._weatherPowerTarget = type === 'none' ? 0 : power;
        this._weatherDuration = duration;
        if (duration === 0) {
            this._weatherPower = this._weatherPowerTarget;
        }
    };

    update(): void {
        this.updateFadeOut();
        this.updateFadeIn();
        this.updateTone();
        this.updateFlash();
        this.updateShake();
        this.updateZoom();
        this.updateWeather();
        this.updatePictures();
    };

    updateFadeOut(): void {
        if (this._fadeOutDuration > 0) {
            var d = this._fadeOutDuration;
            this._brightness = (this._brightness * (d - 1)) / d;
            this._fadeOutDuration--;
        }
    };

    updateFadeIn(): void {
        if (this._fadeInDuration > 0) {
            var d = this._fadeInDuration;
            this._brightness = (this._brightness * (d - 1) + 255) / d;
            this._fadeInDuration--;
        }
    };

    updateTone(): void {
        if (this._toneDuration > 0) {
            var d = this._toneDuration;
            for (var i = 0; i < 4; i++) {
                this._tone[i] = (this._tone[i] * (d - 1) + this._toneTarget[i]) / d;
            }
            this._toneDuration--;
        }
    };

    updateFlash(): void {
        if (this._flashDuration > 0) {
            var d = this._flashDuration;
            this._flashColor[3] *= (d - 1) / d;
            this._flashDuration--;
        }
    };

    updateShake(): void {
        if (this._shakeDuration > 0 || this._shake !== 0) {
            var delta = (this._shakePower * this._shakeSpeed * this._shakeDirection) / 10;
            if (this._shakeDuration <= 1 && this._shake * (this._shake + delta) < 0) {
                this._shake = 0;
            } else {
                this._shake += delta;
            }
            if (this._shake > this._shakePower * 2) {
                this._shakeDirection = -1;
            }
            if (this._shake < - this._shakePower * 2) {
                this._shakeDirection = 1;
            }
            this._shakeDuration--;
        }
    };

    updateZoom(): void {
        if (this._zoomDuration > 0) {
            var d = this._zoomDuration;
            var t = this._zoomScaleTarget;
            this._zoomScale = (this._zoomScale * (d - 1) + t) / d;
            this._zoomDuration--;
        }
    };

    updateWeather(): void {
        if (this._weatherDuration > 0) {
            var d = this._weatherDuration;
            var t = this._weatherPowerTarget;
            this._weatherPower = (this._weatherPower * (d - 1) + t) / d;
            this._weatherDuration--;
            if (this._weatherDuration === 0 && this._weatherPowerTarget === 0) {
                this._weatherType = 'none';
            }
        }
    };

    updatePictures(): void {
        this._pictures.forEach(function(picture) {
            if (picture) {
                picture.update();
            }
        });
    };

    startFlashForDamage(): void {
        this.startFlash([255, 0, 0, 128], 8);
    };

    showPicture(pictureId: number, name: string, origin: number, x: number, y: number, scaleX: number, scaleY: number, opacity: number, blendMode: number): void {
        var realPictureId = this.realPictureId(pictureId);
        var picture = new Game_Picture();
        picture.show(name, origin, x, y, scaleX, scaleY, opacity, blendMode);
        this._pictures[realPictureId] = picture;
    };

    movePicture(pictureId: number, origin: number, x: number, y: number, scaleX: number, scaleY: number, opacity: number, blendMode: number, duration: number): void {
        var picture = this.picture(pictureId);
        if (picture) {
            picture.move(origin, x, y, scaleX, scaleY, opacity, blendMode, duration);
        }
    };

    rotatePicture(pictureId: number, speed: number): void {
        var picture = this.picture(pictureId);
        if (picture) {
            picture.rotate(speed);
        }
    };

    tintPicture(pictureId: number, tone: number[], duration: number): void {
        var picture = this.picture(pictureId);
        if (picture) {
            picture.tint(tone, duration);
        }
    };

    erasePicture(pictureId: number): void {
        var realPictureId = this.realPictureId(pictureId);
        this._pictures[realPictureId] = null;
    };
}

//-----------------------------------------------------------------------------
// Game_Picture
//
// The game object class for a picture.

class Game_Picture {
    constructor() {
        this.initialize.apply(this, arguments);
    }

    initialize(): void {
        this.initBasic();
        this.initTarget();
        this.initTone();
        this.initRotation();
    };

    name(): string {
        return this._name;
    };
    _name: string;
    origin(): number {
        return this._origin;
    };
    _origin: number;
    x(): number {
        return this._x;
    };
    _x: number;
    y(): number {
        return this._y;
    };
    _y: number;
    scaleX(): number {
        return this._scaleX;
    };
    _scaleX: number;
    scaleY(): number {
        return this._scaleY;
    };
    _scaleY: number;
    opacity(): number {
        return this._opacity;
    };
    _opacity: number;
    blendMode(): number {
        return this._blendMode;
    };
    _blendMode: number;
    tone(): number[] {
        return this._tone;
    };
    _tone: number[];
    angle(): number {
        return this._angle;
    };
    _angle: number;

    initBasic(): void {
        this._name = '';
        this._origin = 0;
        this._x = 0;
        this._y = 0;
        this._scaleX = 100;
        this._scaleY = 100;
        this._opacity = 255;
        this._blendMode = 0;
    };
    initTarget(): void {
        this._targetX = this._x;
        this._targetY = this._y;
        this._targetScaleX = this._scaleX;
        this._targetScaleY = this._scaleY;
        this._targetOpacity = this._opacity;
        this._duration = 0;
    };
    _targetX: number;
    _targetY: number;
    _targetScaleX: number;
    _targetScaleY: number;
    _targetOpacity: number;
    _duration: number;
    initTone(): void {
        this._tone = null;
        this._toneTarget = null;
        this._toneDuration = 0;
    };
    _toneTarget: number[]|any;
    _toneDuration: number;
    initRotation(): void {
        this._angle = 0;
        this._rotationSpeed = 0;
    };
    _rotationSpeed: number;
    show(name: string, origin: number, x: number, y: number, scaleX: number, scaleY: number, opacity: number, blendMode: number): void {
        this._name = name;
        this._origin = origin;
        this._x = x;
        this._y = y;
        this._scaleX = scaleX;
        this._scaleY = scaleY;
        this._opacity = opacity;
        this._blendMode = blendMode;
        this.initTarget();
        this.initTone();
        this.initRotation();
    };
    move(origin: number, x: number, y: number, scaleX: number, scaleY: number, opacity: number, blendMode: number, duration: number): void {
        this._origin = origin;
        this._targetX = x;
        this._targetY = y;
        this._targetScaleX = scaleX;
        this._targetScaleY = scaleY;
        this._targetOpacity = opacity;
        this._blendMode = blendMode;
        this._duration = duration;
    };
    rotate(speed: number): void {
        this._rotationSpeed = speed;
    };
    tint(tone: number[], duration: number): void {
        if (!this._tone) {
            this._tone = [0, 0, 0, 0];
        }
        this._toneTarget = tone.clone();
        this._toneDuration = duration;
        if (this._toneDuration === 0) {
            this._tone = this._toneTarget.clone();
        }
    };
    erase(): void {
        this._name = '';
        this._origin = 0;
        this.initTarget();
        this.initTone();
        this.initRotation();
    };
    update(): void {
        this.updateMove();
        this.updateTone();
        this.updateRotation();
    };
    updateMove(): void {
        if (this._duration > 0) {
            var d = this._duration;
            this._x = (this._x * (d - 1) + this._targetX) / d;
            this._y = (this._y * (d - 1) + this._targetY) / d;
            this._scaleX  = (this._scaleX  * (d - 1) + this._targetScaleX)  / d;
            this._scaleY  = (this._scaleY  * (d - 1) + this._targetScaleY)  / d;
            this._opacity = (this._opacity * (d - 1) + this._targetOpacity) / d;
            this._duration--;
        }
    };
    updateTone(): void {
        if (this._toneDuration > 0) {
            var d = this._toneDuration;
            for (var i = 0; i < 4; i++) {
                this._tone[i] = (this._tone[i] * (d - 1) + this._toneTarget[i]) / d;
            }
            this._toneDuration--;
        }
    };
    updateRotation(): void {
        if (this._rotationSpeed !== 0) {
            this._angle += this._rotationSpeed / 2;
        }
    };
}

//-----------------------------------------------------------------------------
// Game_Item
//
// The game object class for handling skills, items, weapons, and armor. It is
// required because save data should not include the database object itself.

class Game_Item {
    constructor(item?: RPGMakerMV.DataAnyItem | RPGMakerMV.DataSkill) {
        this.initialize.apply(this, arguments);
    }
    initialize(item: RPGMakerMV.DataAnyItem | RPGMakerMV.DataSkill): void {
        this._dataClass = '';
        this._itemId = 0;
        if (item) {
            this.setObject(item);
        }
    };
    _dataClass: string;
    _itemId: number;
    isSkill(): boolean {
        return this._dataClass === 'skill';
    };
    isItem(): boolean {
        return this._dataClass === 'item';
    };
    isUsableItem(): boolean {
        return this.isSkill() || this.isItem();
    };
    isWeapon(): boolean {
        return this._dataClass === 'weapon';
    };
    isArmor(): boolean {
        return this._dataClass === 'armor';
    };
    isEquipItem(): boolean {
        return this.isWeapon() || this.isArmor();
    };
    isNull(): boolean {
        return this._dataClass === '';
    };
    itemId(): number {
        return this._itemId;
    };
    object(): RPGMakerMV.DataAnyItem | RPGMakerMV.DataSkill {
        if (this.isSkill()) {
            return $dataSkills[this._itemId];
        } else if (this.isItem()) {
            return $dataItems[this._itemId];
        } else if (this.isWeapon()) {
            return $dataWeapons[this._itemId];
        } else if (this.isArmor()) {
            return $dataArmors[this._itemId];
        } else {
            return null;
        }
    };
    setObject(item: any): void {
        if (DataManager.isSkill(item)) {
            this._dataClass = 'skill';
        } else if (DataManager.isItem(item)) {
            this._dataClass = 'item';
        } else if (DataManager.isWeapon(item)) {
            this._dataClass = 'weapon';
        } else if (DataManager.isArmor(item)) {
            this._dataClass = 'armor';
        } else {
            this._dataClass = '';
        }
        this._itemId = item ? item.id : 0;
    };
    
    setEquip(isWeapon: boolean, itemId: number): void {
        this._dataClass = isWeapon ? 'weapon' : 'armor';
        this._itemId = itemId;
    };
}

//-----------------------------------------------------------------------------
// Game_Action
//
// The game object class for a battle action.

class Game_Action {
    constructor(subject: Game_Battler, forcing?: boolean) {
        this.initialize.apply(this, arguments);
    }
    static EFFECT_RECOVER_HP:number = 11;
    static EFFECT_RECOVER_MP: 12;
    static EFFECT_GAIN_TP: 13;
    static EFFECT_ADD_STATE:number = 21;
    static EFFECT_REMOVE_STATE:number = 22;
    static EFFECT_ADD_BUFF:number = 31;
    static EFFECT_ADD_DEBUFF:number = 32;
    static EFFECT_REMOVE_BUFF:number = 33;
    static EFFECT_REMOVE_DEBUFF:number = 34;
    static EFFECT_SPECIAL:number = 41;
    static EFFECT_GROW:number = 42;
    static EFFECT_LEARN_SKILL:number = 43;
    static EFFECT_COMMON_EVENT:number = 44;
    static SPECIAL_EFFECT_ESCAPE:number = 0;
    static HITTYPE_CERTAIN:number = 0;
    static HITTYPE_PHYSICAL:number = 1;
    static HITTYPE_MAGICAL:number = 2;

    initialize(subject: Game_Battler, forcing: boolean): void {
        this._subjectActorId = 0;
        this._subjectEnemyIndex = -1;
        this._forcing = forcing || false;
        this.setSubject(subject);
        this.clear();
    };
    _subjectActorId: number;
    _subjectEnemyIndex: number;
    _forcing: boolean;
    clear(): void {
        this._item = new Game_Item();
        this._targetIndex = -1;
    };
    _item: Game_Item;
    _targetIndex: number;

    setSubject(subject: Game_Battler|any): void {
        if (subject.isActor()) {
            this._subjectActorId = subject.actorId();
            this._subjectEnemyIndex = -1;
        } else {
            this._subjectEnemyIndex = subject.index();
            this._subjectActorId = 0;
        }
    };
    subject(): Game_Battler|any {
        if (this._subjectActorId > 0) {
            return $gameActors.actor(this._subjectActorId);
        } else {
            return $gameTroop.members()[this._subjectEnemyIndex];
        }
    };
    friendsUnit(): Game_Unit {
        return this.subject().friendsUnit();
    };
    opponentsUnit(): Game_Unit {
        return this.subject().opponentsUnit();
    };
    setEnemyAction(action: boolean|any): void {
        if (action) {
            this.setSkill(action.skillId);
        } else {
            this.clear();
        }
    };
    setAttack(): void {
        this.setSkill(this.subject().attackSkillId());
    };
    setGuard(): void {
        this.setSkill(this.subject().guardSkillId());
    };
    setSkill(skillId: number): void {
        this._item.setObject($dataSkills[skillId]);
    };
    setItem(itemId: number): void {
        this._item.setObject($dataItems[itemId]);
    };
    setItemObject(object: RPGMakerMV.DataAnyItem | RPGMakerMV.DataSkill): void {
        this._item.setObject(object);
    };
    setTarget(targetIndex: number): void {
        this._targetIndex = targetIndex;
    };
    item(): RPGMakerMV.DataAnyItem | RPGMakerMV.DataSkill|any {
        return this._item.object();
    };
    isSkill(): boolean {
        return this._item.isSkill();
    };
    isItem(): boolean {
        return this._item.isItem();
    };
    numRepeats(): number {
        var repeats = this.item().repeats;
        if (this.isAttack()) {
            repeats += this.subject().attackTimesAdd();
        }
        return Math.floor(repeats);
    };
    checkItemScope(list: number[]): boolean {
        return list.contains(this.item().scope);
    };
    isForOpponent(): boolean {
        return this.checkItemScope([1, 2, 3, 4, 5, 6]);
    };
    isForFriend(): boolean {
        return this.checkItemScope([7, 8, 9, 10, 11]);
    };
    isForDeadFriend(): boolean {
        return this.checkItemScope([9, 10]);
    };
    isForUser(): boolean {
        return this.checkItemScope([11]);
    };
    isForOne(): boolean {
        return this.checkItemScope([1, 3, 7, 9, 11]);
    };
    isForRandom(): boolean {
        return this.checkItemScope([3, 4, 5, 6]);
    };
    isForAll(): boolean {
        return this.checkItemScope([2, 8, 10]);
    };
    needsSelection(): boolean {
        return this.checkItemScope([1, 7, 9]);
    };
    numTargets(): number {
        return this.isForRandom() ? this.item().scope - 2 : 0;
    };
    checkDamageType(list: number[]): boolean {
        return list.contains(this.item().damage.type);
    };
    isHpEffect(): boolean {
        return this.checkDamageType([1, 3, 5]);
    };
    isMpEffect(): boolean {
        return this.checkDamageType([2, 4, 6]);
    };
    isDamage(): boolean {
        return this.checkDamageType([1, 2]);
    };
    isRecover(): boolean {
        return this.checkDamageType([3, 4]);
    };
    isDrain(): boolean {
        return this.checkDamageType([5, 6]);
    };
    isHpRecover(): boolean {
        return this.checkDamageType([3]);
    };
    isMpRecover(): boolean {
        return this.checkDamageType([4]);
    };
    isCertainHit(): boolean {
        return this.item().hitType === Game_Action.HITTYPE_CERTAIN;
    };
    isPhysical(): boolean {
        return this.item().hitType === Game_Action.HITTYPE_PHYSICAL;
    };
    isMagical(): boolean {
        return this.item().hitType === Game_Action.HITTYPE_MAGICAL;
    };
    isAttack(): boolean {
        return this.item() === $dataSkills[this.subject().attackSkillId()];
    };
    isGuard(): boolean {
        return this.item() === $dataSkills[this.subject().guardSkillId()];
    };
    isMagicSkill(): boolean {
        if (this.isSkill()) {
            return $dataSystem.magicSkills.contains(this.item().stypeId);
        } else {
            return false;
        }
    };

    decideRandomTarget(): void {
        var target:any;
        if (this.isForDeadFriend()) {
            target = this.friendsUnit().randomDeadTarget();
        } else if (this.isForFriend()) {
            target = this.friendsUnit().randomTarget();
        } else {
            target = this.opponentsUnit().randomTarget();
        }
        if (target) {
            this._targetIndex = target.index();
        } else {
            this.clear();
        }
    };
    setConfusion(): void {
        this.setAttack();
    };
    prepare(): void {
        if (this.subject().isConfused() && !this._forcing) {
            this.setConfusion();
        }
    };
    isValid(): boolean {
        return (this._forcing && this.item()) || this.subject().canUse(this.item());
    };
    speed(): number {
        var agi = this.subject().agi;
        var speed = agi + Math.randomInt(Math.floor(5 + agi / 4));
        if (this.item()) {
            speed += this.item().speed;
        }
        if (this.isAttack()) {
            speed += this.subject().attackSpeed();
        }
        return speed;
    };
    makeTargets(): Game_Battler[] {
        var targets:any = [];
        if (!this._forcing && this.subject().isConfused()) {
            targets = [this.confusionTarget()];
        } else if (this.isForOpponent()) {
            targets = this.targetsForOpponents();
        } else if (this.isForFriend()) {
            targets = this.targetsForFriends();
        }
        return this.repeatTargets(targets);
    };
    repeatTargets(targets: Game_Battler[]): Game_Battler[] {
        var repeatedTargets = [];
        var repeats = this.numRepeats();
        for (var i = 0; i < targets.length; i++) {
            var target = targets[i];
            if (target) {
                for (var j = 0; j < repeats; j++) {
                    repeatedTargets.push(target);
                }
            }
        }
        return repeatedTargets;
    };
    confusionTarget(): Game_Battler {
        switch (this.subject().confusionLevel()) {
        case 1:
            return this.opponentsUnit().randomTarget();
        case 2:
            if (Math.randomInt(2) === 0) {
                return this.opponentsUnit().randomTarget();
            }
            return this.friendsUnit().randomTarget();
        default:
            return this.friendsUnit().randomTarget();
        }
    };
    targetsForOpponents(): Game_Battler[] {
        var targets = [];
        var unit = this.opponentsUnit();
        if (this.isForRandom()) {
            for (var i = 0; i < this.numTargets(); i++) {
                targets.push(unit.randomTarget());
            }
        } else if (this.isForOne()) {
            if (this._targetIndex < 0) {
                targets.push(unit.randomTarget());
            } else {
                targets.push(unit.smoothTarget(this._targetIndex));
            }
        } else {
            targets = unit.aliveMembers();
        }
        return targets;
    };
    targetsForFriends(): Game_Battler[] {
        var targets = [];
        var unit = this.friendsUnit();
        if (this.isForUser()) {
            return [this.subject()];
        } else if (this.isForDeadFriend()) {
            if (this.isForOne()) {
                targets.push(unit.smoothDeadTarget(this._targetIndex));
            } else {
                targets = unit.deadMembers();
            }
        } else if (this.isForOne()) {
            if (this._targetIndex < 0) {
                targets.push(unit.randomTarget());
            } else {
                targets.push(unit.smoothTarget(this._targetIndex));
            }
        } else {
            targets = unit.aliveMembers();
        }
        return targets;
    };
    evaluate(): number {
        var value = 0;
        this.itemTargetCandidates().forEach((target:Game_Battler|any)=> {
            var targetValue = this.evaluateWithTarget(target);
            if (this.isForAll()) {
                value += targetValue;
            } else if (targetValue > value) {
                value = targetValue;
                this._targetIndex = target.index();
            }
        }, this);
        value *= this.numRepeats();
        if (value > 0) {
            value += Math.random();
        }
        return value;
    };
    itemTargetCandidates(): Game_Battler[] {
        if (!this.isValid()) {
            return [];
        } else if (this.isForOpponent()) {
            return this.opponentsUnit().aliveMembers();
        } else if (this.isForUser()) {
            return [this.subject()];
        } else if (this.isForDeadFriend()) {
            return this.friendsUnit().deadMembers();
        } else {
            return this.friendsUnit().aliveMembers();
        }
    };
    evaluateWithTarget(target: Game_Battler): number {
        if (this.isHpEffect()) {
            var value = this.makeDamageValue(target, false);
            if (this.isForOpponent()) {
                return value / Math.max(target.hp, 1);
            } else {
                var recovery = Math.min(-value, target.mhp - target.hp);
                return recovery / target.mhp;
            }
        }
    };
    testApply(target: Game_Battler): boolean|any {
        return (this.isForDeadFriend() === target.isDead() &&
                ($gameParty.inBattle() || this.isForOpponent() ||
                (this.isHpRecover() && target.hp < target.mhp) ||
                (this.isMpRecover() && target.mp < target.mmp) ||
                (this.hasItemAnyValidEffects(target))));
    };
    hasItemAnyValidEffects(target: Game_Battler): number {
        return this.item().effects.some((effect:RPGMakerMV.Effect)=> {
            return this.testItemEffect(target, effect);
        }, this);
    };
    testItemEffect(target: Game_Battler|any, effect: RPGMakerMV.Effect): number|any {
        switch (effect.code) {
        case Game_Action.EFFECT_RECOVER_HP:
            return target.hp < target.mhp || effect.value1 < 0 || effect.value2 < 0;
        case Game_Action.EFFECT_RECOVER_MP:
            return target.mp < target.mmp || effect.value1 < 0 || effect.value2 < 0;
        case Game_Action.EFFECT_ADD_STATE:
            return !target.isStateAffected(effect.dataId);
        case Game_Action.EFFECT_REMOVE_STATE:
            return target.isStateAffected(effect.dataId);
        case Game_Action.EFFECT_ADD_BUFF:
            return !target.isMaxBuffAffected(effect.dataId);
        case Game_Action.EFFECT_ADD_DEBUFF:
            return !target.isMaxDebuffAffected(effect.dataId);
        case Game_Action.EFFECT_REMOVE_BUFF:
            return target.isBuffAffected(effect.dataId);
        case Game_Action.EFFECT_REMOVE_DEBUFF:
            return target.isDebuffAffected(effect.dataId);
        case Game_Action.EFFECT_LEARN_SKILL:
            return target.isActor() && !target.isLearnedSkill(effect.dataId);
        default:
            return true;
        }
    };
    itemCnt(target: Game_Battler): number {
        if (this.isPhysical() && target.canMove()) {
            return target.cnt;
        } else {
            return 0;
        }
    };
    itemMrf(target: Game_Battler): number {
        if (this.isMagical()) {
            return target.mrf;
        } else {
            return 0;
        }
    };
    itemHit(target: Game_Battler): number {
        if (this.isPhysical()) {
            return this.item().successRate * 0.01 * this.subject().hit;
        } else {
            return this.item().successRate * 0.01;
        }
    };

    itemEva(target: Game_Battler): number {
        if (this.isPhysical()) {
            return target.eva;
        } else if (this.isMagical()) {
            return target.mev;
        } else {
            return 0;
        }
    };
    itemCri(target: Game_Battler): number {
        return this.item().damage.critical ? this.subject().cri * (1 - target.cev) : 0;
    };
    apply(target: Game_Battler): void {
        var result = target.result();
        this.subject().clearResult();
        result.clear();
        result.used = this.testApply(target);
        result.missed = (result.used && Math.random() >= this.itemHit(target));
        result.evaded = (!result.missed && Math.random() < this.itemEva(target));
        result.physical = this.isPhysical();
        result.drain = this.isDrain();
        if (result.isHit()) {
            if (this.item().damage.type > 0) {
                result.critical = (Math.random() < this.itemCri(target));
                var value = this.makeDamageValue(target, result.critical);
                this.executeDamage(target, value);
            }
            this.item().effects.forEach((effect:RPGMakerMV.Effect)=> {
                this.applyItemEffect(target, effect);
            }, this);
            this.applyItemUserEffect(target);
        }
    };
    makeDamageValue(target: Game_Battler, critical: boolean): number {
        var item = this.item();
        var baseValue = this.evalDamageFormula(target);
        var value = baseValue * this.calcElementRate(target);
        if (this.isPhysical()) {
            value *= target.pdr;
        }
        if (this.isMagical()) {
            value *= target.mdr;
        }
        if (baseValue < 0) {
            value *= target.rec;
        }
        if (critical) {
            value = this.applyCritical(value);
        }
        value = this.applyVariance(value, item.damage.variance);
        value = this.applyGuard(value, target);
        value = Math.round(value);
        return value;
    };
    evalDamageFormula(target: Game_Battler): number {
        try {
            var item = this.item();
            var a = this.subject();
            var b = target;
            var v = $gameVariables._data;
            var sign = ([3, 4].contains(item.damage.type) ? -1 : 1);
            var value = Math.max(eval(item.damage.formula), 0) * sign;
            if (isNaN(value)) value = 0;
            return value;
        } catch (e) {
            return 0;
        }
    };
    calcElementRate(target: Game_Battler): number {
        if (this.item().damage.elementId < 0) {
            return this.elementsMaxRate(target, this.subject().attackElements());
        } else {
            return target.elementRate(this.item().damage.elementId);
        }
    };
    elementsMaxRate(target: Game_Battler, elements: number[]): number {
        if (elements.length > 0) {
            return Math.max.apply(null, elements.map(function(elementId) {
                return target.elementRate(elementId);
            }, this));
        } else {
            return 1;
        }
    };
    applyCritical(damage: number): number {
        return damage * 3;
    };

    applyVariance(damage: number, variance: number): number {
        var amp = Math.floor(Math.max(Math.abs(damage) * variance / 100, 0));
        var v = Math.randomInt(amp + 1) + Math.randomInt(amp + 1) - amp;
        return damage >= 0 ? damage + v : damage - v;
    };
    applyGuard(damage: number, target: Game_Battler): number {
        return damage / (damage > 0 && target.isGuard() ? 2 * target.grd : 1);
    };
    executeDamage(target: Game_Battler, value: number): void {
        var result = target.result();
        if (value === 0) {
            result.critical = false;
        }
        if (this.isHpEffect()) {
            this.executeHpDamage(target, value);
        }
        if (this.isMpEffect()) {
            this.executeMpDamage(target, value);
        }
    };
    executeHpDamage(target: Game_Battler, value: number): void {
        if (this.isDrain()) {
            value = Math.min(target.hp, value);
        }
        this.makeSuccess(target);
        target.gainHp(-value);
        if (value > 0) {
            target.onDamage(value);
        }
        this.gainDrainedHp(value);
    };
    executeMpDamage(target: Game_Battler, value: number): void {
        if (!this.isMpRecover()) {
            value = Math.min(target.mp, value);
        }
        if (value !== 0) {
            this.makeSuccess(target);
        }
        target.gainMp(-value);
        this.gainDrainedMp(value);
    };
    _reflectionTarget:any;
    gainDrainedHp(value: number): void {
        if (this.isDrain()) {
           var gainTarget = this.subject();
           if (this._reflectionTarget !== undefined) {
                gainTarget = this._reflectionTarget;
            }
           gainTarget.gainHp(value);
        }
    };
    gainDrainedMp(value: number): void {
        if (this.isDrain()) {
           var gainTarget = this.subject();
           if (this._reflectionTarget !== undefined) {
               gainTarget = this._reflectionTarget;
           }
           gainTarget.gainMp(value);
        }
    };
    applyItemEffect(target: Game_Battler, effect: RPGMakerMV.Effect): void {
        switch (effect.code) {
        case Game_Action.EFFECT_RECOVER_HP:
            this.itemEffectRecoverHp(target, effect);
            break;
        case Game_Action.EFFECT_RECOVER_MP:
            this.itemEffectRecoverMp(target, effect);
            break;
        case Game_Action.EFFECT_GAIN_TP:
            this.itemEffectGainTp(target, effect);
            break;
        case Game_Action.EFFECT_ADD_STATE:
            this.itemEffectAddState(target, effect);
            break;
        case Game_Action.EFFECT_REMOVE_STATE:
            this.itemEffectRemoveState(target, effect);
            break;
        case Game_Action.EFFECT_ADD_BUFF:
            this.itemEffectAddBuff(target, effect);
            break;
        case Game_Action.EFFECT_ADD_DEBUFF:
            this.itemEffectAddDebuff(target, effect);
            break;
        case Game_Action.EFFECT_REMOVE_BUFF:
            this.itemEffectRemoveBuff(target, effect);
            break;
        case Game_Action.EFFECT_REMOVE_DEBUFF:
            this.itemEffectRemoveDebuff(target, effect);
            break;
        case Game_Action.EFFECT_SPECIAL:
            this.itemEffectSpecial(target, effect);
            break;
        case Game_Action.EFFECT_GROW:
            this.itemEffectGrow(target, effect);
            break;
        case Game_Action.EFFECT_LEARN_SKILL:
            this.itemEffectLearnSkill(target, effect);
            break;
        case Game_Action.EFFECT_COMMON_EVENT:
            this.itemEffectCommonEvent(target, effect);
            break;
        }
    };
    itemEffectRecoverHp(target: Game_Battler, effect: RPGMakerMV.Effect): void {
        var value = (target.mhp * effect.value1 + effect.value2) * target.rec;
        if (this.isItem()) {
            value *= this.subject().pha;
        }
        value = Math.floor(value);
        if (value !== 0) {
            target.gainHp(value);
            this.makeSuccess(target);
        }
    };
    itemEffectRecoverMp(target: Game_Battler, effect: RPGMakerMV.Effect): void {
        var value = (target.mmp * effect.value1 + effect.value2) * target.rec;
        if (this.isItem()) {
            value *= this.subject().pha;
        }
        value = Math.floor(value);
        if (value !== 0) {
            target.gainMp(value);
            this.makeSuccess(target);
        }
    };
    itemEffectGainTp(target: Game_Battler, effect: RPGMakerMV.Effect): void {
        var value = Math.floor(effect.value1);
        if (value !== 0) {
            target.gainTp(value);
            this.makeSuccess(target);
        }
    };
    itemEffectAddState(target: Game_Battler, effect: RPGMakerMV.Effect): void {
        if (effect.dataId === 0) {
            this.itemEffectAddAttackState(target, effect);
        } else {
            this.itemEffectAddNormalState(target, effect);
        }
    };
    itemEffectAddAttackState(target: Game_Battler|any, effect: RPGMakerMV.Effect): void {
        this.subject().attackStates().forEach(function(this:any, stateId:number) {
            var chance = effect.value1;
            chance *= target.stateRate(stateId);
            chance *= this.subject().attackStatesRate(stateId);
            chance *= this.lukEffectRate(target);
            if (Math.random() < chance) {
                target.addState(stateId);
                this.makeSuccess(target);
            }
        }.bind(this), target);
    };
    itemEffectAddNormalState(target: Game_Battler, effect: RPGMakerMV.Effect): void {
        var chance = effect.value1;
        if (!this.isCertainHit()) {
            chance *= target.stateRate(effect.dataId);
            chance *= this.lukEffectRate(target);
        }
        if (Math.random() < chance) {
            target.addState(effect.dataId);
            this.makeSuccess(target);
        }
    };
    itemEffectRemoveState(target: Game_Battler, effect: RPGMakerMV.Effect): void {
        var chance = effect.value1;
        if (Math.random() < chance) {
            target.removeState(effect.dataId);
            this.makeSuccess(target);
        }
    };
    itemEffectAddBuff(target: Game_Battler, effect: RPGMakerMV.Effect): void {
        target.addBuff(effect.dataId, effect.value1);
        this.makeSuccess(target);
    };
    itemEffectAddDebuff(target: Game_Battler, effect: RPGMakerMV.Effect): void {
        var chance = target.debuffRate(effect.dataId) * this.lukEffectRate(target);
        if (Math.random() < chance) {
            target.addDebuff(effect.dataId, effect.value1);
            this.makeSuccess(target);
        }
    };
    itemEffectRemoveBuff(target: Game_Battler, effect: RPGMakerMV.Effect): void {
        if (target.isBuffAffected(effect.dataId)) {
            target.removeBuff(effect.dataId);
            this.makeSuccess(target);
        }
    };
    itemEffectRemoveDebuff(target: Game_Battler, effect: RPGMakerMV.Effect): void {
        if (target.isDebuffAffected(effect.dataId)) {
            target.removeBuff(effect.dataId);
            this.makeSuccess(target);
        }
    };
    itemEffectSpecial(target: Game_Battler, effect: RPGMakerMV.Effect): void {
        if (effect.dataId === Game_Action.SPECIAL_EFFECT_ESCAPE) {
            target.escape();
            this.makeSuccess(target);
        }
    };
    itemEffectGrow(target: Game_Battler, effect: RPGMakerMV.Effect): void {
        target.addParam(effect.dataId, Math.floor(effect.value1));
        this.makeSuccess(target);
    };
    itemEffectLearnSkill(target: Game_Battler|any, effect: RPGMakerMV.Effect): void {
        if (target.isActor()) {
            target.learnSkill(effect.dataId);
            this.makeSuccess(target);
        }
    };
    itemEffectCommonEvent(target: Game_Battler, effect: RPGMakerMV.Effect): void {
    };
    makeSuccess(target: Game_Battler): void {
        target.result().success = true;
    };
    applyItemUserEffect(target: Game_Battler): void {
        var value = Math.floor(this.item().tpGain * this.subject().tcr);
        this.subject().gainSilentTp(value);
    };
    lukEffectRate(target: Game_Battler): number {
        return Math.max(1.0 + (this.subject().luk - target.luk) * 0.001, 0.0);
    };
    applyGlobal(): void {
        this.item().effects.forEach((effect:any)=> {
            if (effect.code === Game_Action.EFFECT_COMMON_EVENT) {
                $gameTemp.reserveCommonEvent(effect.dataId);
            }
        }, this);
    };
}

//-----------------------------------------------------------------------------
// Game_ActionResult
//
// The game object class for a result of a battle action. For convinience, all
// member variables in this class are public.

class Game_ActionResult {
    constructor() {
        this.initialize.apply(this, arguments);
    }
    initialize(): void {
        this.clear();
    };
    clear(): void {
        this.used = false;
        this.missed = false;
        this.evaded = false;
        this.physical = false;
        this.drain = false;
        this.critical = false;
        this.success = false;
        this.hpAffected = false;
        this.hpDamage = 0;
        this.mpDamage = 0;
        this.tpDamage = 0;
        this.addedStates = [];
        this.removedStates = [];
        this.addedBuffs = [];
        this.addedDebuffs = [];
        this.removedBuffs = [];
    };
    used: boolean;
    missed: boolean;
    evaded: boolean;
    physical: boolean;
    drain: boolean;
    critical: boolean;
    success: boolean;
    hpAffected: boolean;
    hpDamage: number;
    mpDamage: number;
    tpDamage: number;
    addedStates: RPGMakerMV.DataState[];
    removedStates: RPGMakerMV.DataState[];
    addedBuffs: number[];
    addedDebuffs: number[];
    removedBuffs: number[];

    addedStateObjects(): RPGMakerMV.DataState[] {
        return this.addedStates.map((id:any)=> {
            return $dataStates[id];
        });
    };
    removedStateObjects(): RPGMakerMV.DataState[] {
        return this.removedStates.map((id:any) =>{
            return $dataStates[id];
        });
    };
    isStatusAffected(): boolean {
        return (this.addedStates.length > 0 || this.removedStates.length > 0 ||
                this.addedBuffs.length > 0 || this.addedDebuffs.length > 0 ||
                this.removedBuffs.length > 0);
    };
    isHit(): boolean {
        return this.used && !this.missed && !this.evaded;
    };
    isStateAdded(stateId: any): boolean {
        return this.addedStates.contains(stateId);
    };
    pushAddedState(stateId: any): void {
        if (!this.isStateAdded(stateId)) {
            this.addedStates.push(stateId);
        }
    };
    isStateRemoved(stateId: any): boolean {
        return this.removedStates.contains(stateId);
    };
    pushRemovedState(stateId: any): void {
        if (!this.isStateRemoved(stateId)) {
            this.removedStates.push(stateId);
        }
    };
    isBuffAdded(paramId: number): boolean {
        return this.addedBuffs.contains(paramId);
    };
    pushAddedBuff(paramId: number): void {
        if (!this.isBuffAdded(paramId)) {
            this.addedBuffs.push(paramId);
        }
    };
    isDebuffAdded(paramId: number): boolean {
        return this.addedDebuffs.contains(paramId);
    };
    pushAddedDebuff(paramId: number): void {
        if (!this.isDebuffAdded(paramId)) {
            this.addedDebuffs.push(paramId);
        }
    };
    isBuffRemoved(paramId: number): boolean {
        return this.removedBuffs.contains(paramId);
    };
    pushRemovedBuff(paramId: number): void {
        if (!this.isBuffRemoved(paramId)) {
            this.removedBuffs.push(paramId);
        }
    };
}

//-----------------------------------------------------------------------------
// Game_BattlerBase
//
// The superclass of Game_Battler. It mainly contains parameters calculation.

class Game_BattlerBase {
    //constructor() {
    //    this.initialize.apply(this, arguments);
    //}
    constructor(...args: any[]) {
        this.initialize(...args);
    }
    static TRAIT_ELEMENT_RATE:number = 11;
    static TRAIT_DEBUFF_RATE:number = 12;
    static TRAIT_STATE_RATE:number = 13;
    static TRAIT_STATE_RESIST:number = 14;
    static TRAIT_PARAM:number = 21;
    static TRAIT_XPARAM:number = 22;
    static TRAIT_SPARAM:number = 23;
    static TRAIT_ATTACK_ELEMENT:number = 31;
    static TRAIT_ATTACK_STATE:number = 32;
    static TRAIT_ATTACK_SPEED:number = 33;
    static TRAIT_ATTACK_TIMES:number = 34;
    static TRAIT_STYPE_ADD:number = 41;
    static TRAIT_STYPE_SEAL:number = 42;
    static TRAIT_SKILL_ADD:number = 43;
    static TRAIT_SKILL_SEAL:number = 44;
    static TRAIT_EQUIP_WTYPE:number = 51;
    static TRAIT_EQUIP_ATYPE:number = 52;
    static TRAIT_EQUIP_LOCK:number = 53;
    static TRAIT_EQUIP_SEAL:number = 54;
    static TRAIT_SLOT_TYPE:number = 55;
    static TRAIT_ACTION_PLUS:number = 61;
    static TRAIT_SPECIAL_FLAG:number = 62;
    static TRAIT_COLLAPSE_TYPE:number = 63;
    static TRAIT_PARTY_ABILITY:number = 64;
    static FLAG_ID_AUTO_BATTLE:number = 0;
    static FLAG_ID_GUARD:number = 1;
    static FLAG_ID_SUBSTITUTE:number = 2;
    static FLAG_ID_PRESERVE_TP:number = 3;
    static ICON_BUFF_START:number = 32;
    static ICON_DEBUFF_START:number = 48;
    // Hit Points
    //hp: number;
    public get hp():number {
        return this._hp; 
    }
    // Magic Points
    public get mp():number {
        return this._mp; 
    }
    // Tactical Points
    public get tp():number {
        return this._tp; 
    }
    // Maximum Hit Points
    public get mhp():number {
        return this.param(0);
    }
    // Maximum Magic Points
    public get mmp():number {
        return this.param(1);
    }
    // ATtacK power
    public get atk():number {
        return this.param(2);
    }
    // DEFense power
    public get def():number {
        return this.param(3); 
    }
    // Magic ATtack power
    public get mat():number {
        return this.param(4); 
    }
    // Magic DeFense power
    public get mdf():number {
        return this.param(5);
    }
    // AGIlity
    public get agi():number {
        return this.param(6); 
    }
    // LUcK
    public get luk():number {
        return this.param(7);
    }
    // HIT rate
    public get hit():number {
        return this.xparam(0);
    }
    // EVAsion rate
    public get eva():number {
        return this.xparam(1);
    }
    // CRItical rate
    public get cri():number {
        return this.xparam(2); 
    }
    // Critical EVasion rate
    public get cev():number {
        return this.xparam(3); 
    }
    // Magic EVasion rate
    public get mev():number {
        return this.xparam(4); 
    }
    // Magic ReFlection rate
    public get mrf():number {
        return this.xparam(5); 
    }
    // CouNTer attack rate
    public get cnt():number {
        return this.xparam(6);
    }
    // Hp ReGeneration rate
    public get hrg():number {
        return this.xparam(7); 
    }
    // Mp ReGeneration rate
    public get mrg():number {
        return this.xparam(8); 
    }
    // Tp ReGeneration rate
    public get trg():number {
        return this.xparam(9); 
    }
    // TarGet Rate
    public get tgr():number {
        return this.sparam(0); 
    }
    // GuaRD effect rate
    public get grd():number {
        return this.sparam(1); 
    }
    // RECovery effect rate
    public get rec():number {
        return this.sparam(2); 
    }
    // PHArmacology
    public get pha():number {
        return this.sparam(3); 
    }
    // Mp Cost Rate
    public get mcr():number {
        return this.sparam(4); 
    }
    // Tp Charge Rate
    public get tcr():number {
        return this.sparam(5); 
    }
    // Physical Damage Rate
    public get pdr():number {
        return this.sparam(6); 
    }
    // Magical Damage Rate
    public get mdr():number {
        return this.sparam(7); 
    }
    // Floor Damage Rate
    public get fdr():number {
        return this.sparam(8); 
    }
    // EXperience Rate
    public get exr():number {
        return this.sparam(9); 
    }

    _hp: number;
    _mp: number;
    _tp: number;
    _hidden: boolean;
    _paramPlus: number[];
    _states: number[];
    _stateTurns: { [key: number]: number };
    _buffs: number[];
    _buffTurns: number[];

    initialize(...args: any[]): void {
        this.initMembers();
    };
    initMembers(): void {
        this._hp = 1;
        this._mp = 0;
        this._tp = 0;
        this._hidden = false;
        this.clearParamPlus();
        this.clearStates();
        this.clearBuffs();
    };
    clearParamPlus(): void {
        this._paramPlus = [0,0,0,0,0,0,0,0];
    };
    clearStates(): void {
        this._states = [];
        this._stateTurns = {};
    };
    eraseState(stateId: number): void {
        var index = this._states.indexOf(stateId);
        if (index >= 0) {
            this._states.splice(index, 1);
        }
        delete this._stateTurns[stateId];
    };
    isStateAffected(stateId: number): boolean {
        return this._states.contains(stateId);
    };
    isDeathStateAffected(): boolean {
        return this.isStateAffected(this.deathStateId());
    };
    deathStateId(): number {
        return 1;
    };
    
    resetStateCounts(stateId: number): void {
        var state = $dataStates[stateId];
        var variance = 1 + Math.max(state.maxTurns - state.minTurns, 0);
        this._stateTurns[stateId] = state.minTurns + Math.randomInt(variance);
    };
    isStateExpired(stateId: number): boolean {
        return this._stateTurns[stateId] === 0;
    };
    updateStateTurns(): void {
        this._states.forEach((stateId:number)=> {
            if (this._stateTurns[stateId] > 0) {
                this._stateTurns[stateId]--;
            }
        }, this);
    };
    clearBuffs(): void {
        this._buffs = [0,0,0,0,0,0,0,0];
        this._buffTurns = [0,0,0,0,0,0,0,0];
    };
    eraseBuff(paramId: number): void {
        this._buffs[paramId] = 0;
        this._buffTurns[paramId] = 0;
    };
    buffLength(): number {
        return this._buffs.length;
    };
    buff(paramId: number): number {
        return this._buffs[paramId];
    };
    isBuffAffected(paramId: number): boolean {
        return this._buffs[paramId] > 0;
    };
    isDebuffAffected(paramId: number): boolean {
        return this._buffs[paramId] < 0;
    };
    isBuffOrDebuffAffected(paramId: number): boolean {
        return this._buffs[paramId] !== 0;
    };
    isMaxBuffAffected(paramId: number): boolean {
        return this._buffs[paramId] === 2;
    };
    isMaxDebuffAffected(paramId: number): boolean {
        return this._buffs[paramId] === -2;
    };
    increaseBuff(paramId: number): void {
        if (!this.isMaxBuffAffected(paramId)) {
            this._buffs[paramId]++;
        }
    };
    decreaseBuff(paramId: number): void {
        if (!this.isMaxDebuffAffected(paramId)) {
            this._buffs[paramId]--;
        }
    };
    overwriteBuffTurns(paramId: number, turns: number): void {
        if (this._buffTurns[paramId] < turns) {
            this._buffTurns[paramId] = turns;
        }
    };
    isBuffExpired(paramId: number): boolean {
        return this._buffTurns[paramId] === 0;
    };
    updateBuffTurns(): void {
        for (var i = 0; i < this._buffTurns.length; i++) {
            if (this._buffTurns[i] > 0) {
                this._buffTurns[i]--;
            }
        }
    };
    die(): void {
        this._hp = 0;
        this.clearStates();
        this.clearBuffs();
    };
    revive(): void {
        if (this._hp === 0) {
            this._hp = 1;
        }
    };
    states(): RPGMakerMV.DataState[] {
        return this._states.map(function(id) {
            return $dataStates[id];
        });
    };
    stateIcons(): number[] {
        return this.states().map(function(state) {
            return state.iconIndex;
        }).filter(function(iconIndex) {
            return iconIndex > 0;
        });
    };
    buffIcons(): number[] {
        var icons = [];
        for (var i = 0; i < this._buffs.length; i++) {
            if (this._buffs[i] !== 0) {
                icons.push(this.buffIconIndex(this._buffs[i], i));
            }
        }
        return icons;
    };
    buffIconIndex(buffLevel: number, paramId: number): number {
        if (buffLevel > 0) {
            return Game_BattlerBase.ICON_BUFF_START + (buffLevel - 1) * 8 + paramId;
        } else if (buffLevel < 0) {
            return Game_BattlerBase.ICON_DEBUFF_START + (-buffLevel - 1) * 8 + paramId;
        } else {
            return 0;
        }
    };
    allIcons(): number[] {
        return this.stateIcons().concat(this.buffIcons());
    };
    traitObjects(): RPGMakerMV.DataState[] {
        // Returns an array of the all objects having traits. States only here.
        return this.states();
    };
    allTraits(): RPGMakerMV.Trait[] {
        return this.traitObjects().reduce(function(r, obj) {
            return r.concat(obj.traits);
        }, []);
    };
    traits(code: number): RPGMakerMV.Trait[] {
        return this.allTraits().filter(function(trait) {
            return trait.code === code;
        });
    };
    traitsWithId(code: number, id: number): RPGMakerMV.Trait[] {
        return this.allTraits().filter(function(trait) {
            return trait.code === code && trait.dataId === id;
        });
    };
    traitsPi(code: number, id: number): number {
        return this.traitsWithId(code, id).reduce(function(r, trait) {
            return r * trait.value;
        }, 1);
    };
    traitsSum(code: number, id: number): number {
        return this.traitsWithId(code, id).reduce(function(r, trait) {
            return r + trait.value;
        }, 0);
    };
    traitsSumAll(code: number): number {
        return this.traits(code).reduce(function(r, trait) {
            return r + trait.value;
        }, 0);
    };
    traitsSet(code: number): number[] {
        return this.traits(code).reduce(function(r, trait) {
            return r.concat(trait.dataId);
        }, []);
    };
    paramBase(paramId: number): number {
        return 0;
    };
    paramPlus(paramId: number): number {
        return this._paramPlus[paramId];
    };
    paramMin(paramId: number): number {
        if (paramId === 1) {
            return 0;   // MMP
        } else {
            return 1;
        }
    };
    paramMax(paramId: number): number {
        if (paramId === 0) {
            return 999999;  // MHP
        } else if (paramId === 1) {
            return 9999;    // MMP
        } else {
            return 999;
        }
    };
    paramRate(paramId: number): number {
        return this.traitsPi(Game_BattlerBase.TRAIT_PARAM, paramId);
    };
    paramBuffRate(paramId: number): number {
        return this._buffs[paramId] * 0.25 + 1.0;
    };
    param(paramId: number): number {
        var value = this.paramBase(paramId) + this.paramPlus(paramId);
        value *= this.paramRate(paramId) * this.paramBuffRate(paramId);
        var maxValue = this.paramMax(paramId);
        var minValue = this.paramMin(paramId);
        return Math.round(value.clamp(minValue, maxValue));
    };
    xparam(xparamId: number): number {
        return this.traitsSum(Game_BattlerBase.TRAIT_XPARAM, xparamId);
    };
    sparam(sparamId: number): number {
        return this.traitsPi(Game_BattlerBase.TRAIT_SPARAM, sparamId);
    };
    elementRate(elementId: number): number {
        return this.traitsPi(Game_BattlerBase.TRAIT_ELEMENT_RATE, elementId);
    };
    debuffRate(paramId: number): number {
        return this.traitsPi(Game_BattlerBase.TRAIT_DEBUFF_RATE, paramId);
    };
    stateRate(stateId: number): number {
        return this.traitsPi(Game_BattlerBase.TRAIT_STATE_RATE, stateId);
    };
    stateResistSet(): number[] {
        return this.traitsSet(Game_BattlerBase.TRAIT_STATE_RESIST);
    };
    isStateResist(stateId: number): boolean {
        return this.stateResistSet().contains(stateId);
    };
    attackElements(): number[] {
        return this.traitsSet(Game_BattlerBase.TRAIT_ATTACK_ELEMENT);
    };
    attackStates(): number[] {
        return this.traitsSet(Game_BattlerBase.TRAIT_ATTACK_STATE);
    };
    attackStatesRate(stateId: number): number {
        return this.traitsSum(Game_BattlerBase.TRAIT_ATTACK_STATE, stateId);
    };
    attackSpeed(): number {
        return this.traitsSumAll(Game_BattlerBase.TRAIT_ATTACK_SPEED);
    };
    attackTimesAdd(): number {
        return Math.max(this.traitsSumAll(Game_BattlerBase.TRAIT_ATTACK_TIMES), 0);
    };
    addedSkillTypes(): number[] {
        return this.traitsSet(Game_BattlerBase.TRAIT_STYPE_ADD);
    };
    isSkillTypeSealed(stypeId: number): boolean {
        return this.traitsSet(Game_BattlerBase.TRAIT_STYPE_SEAL).contains(stypeId);
    };
    addedSkills(): number[] {
        return this.traitsSet(Game_BattlerBase.TRAIT_SKILL_ADD);
    };
    isSkillSealed(skillId: number): boolean {
        return this.traitsSet(Game_BattlerBase.TRAIT_SKILL_SEAL).contains(skillId);
    };
    isEquipWtypeOk(wtypeId: number): boolean {
        return this.traitsSet(Game_BattlerBase.TRAIT_EQUIP_WTYPE).contains(wtypeId);
    };
    isEquipAtypeOk(atypeId: number): boolean {
        return this.traitsSet(Game_BattlerBase.TRAIT_EQUIP_ATYPE).contains(atypeId);
    };
    isEquipTypeLocked(etypeId: number): boolean {
        return this.traitsSet(Game_BattlerBase.TRAIT_EQUIP_LOCK).contains(etypeId);
    };
    isEquipTypeSealed(etypeId: number): boolean {
        return this.traitsSet(Game_BattlerBase.TRAIT_EQUIP_SEAL).contains(etypeId);
    };
    slotType(): number {
        var set = this.traitsSet(Game_BattlerBase.TRAIT_SLOT_TYPE);
        return set.length > 0 ? Math.max.apply(null, set) : 0;
    };
    isDualWield(): boolean {
        return this.slotType() === 1;
    };
    actionPlusSet(): number[] {
        return this.traits(Game_BattlerBase.TRAIT_ACTION_PLUS).map(function(trait) {
            return trait.value;
        });
    };
    specialFlag(flagId: number): boolean {
        return this.traits(Game_BattlerBase.TRAIT_SPECIAL_FLAG).some(function(trait) {
            return trait.dataId === flagId;
        });
    };
    collapseType(): number {
        var set = this.traitsSet(Game_BattlerBase.TRAIT_COLLAPSE_TYPE);
        return set.length > 0 ? Math.max.apply(null, set) : 0;
    };
    partyAbility(abilityId: number): boolean {
        return this.traits(Game_BattlerBase.TRAIT_PARTY_ABILITY).some(function(trait) {
            return trait.dataId === abilityId;
        });
    };
    isAutoBattle(): boolean {
        return this.specialFlag(Game_BattlerBase.FLAG_ID_AUTO_BATTLE);
    };
    isGuard(): boolean {
        return this.specialFlag(Game_BattlerBase.FLAG_ID_GUARD) && this.canMove();
    };
    isSubstitute(): boolean {
        return this.specialFlag(Game_BattlerBase.FLAG_ID_SUBSTITUTE) && this.canMove();
    };
    isPreserveTp(): boolean {
        return this.specialFlag(Game_BattlerBase.FLAG_ID_PRESERVE_TP);
    };
    addParam(paramId: number, value: number): void {
        this._paramPlus[paramId] += value;
        this.refresh();
    };
    setHp(hp: number): void {
        this._hp = hp;
        this.refresh();
    };
    setMp(mp: number): void {
        this._mp = mp;
        this.refresh();
    };
    setTp(tp: number): void {
        this._tp = tp;
        this.refresh();
    };
    maxTp(): number {
        return 100;
    };
    refresh(): void {
        this.stateResistSet().forEach((stateId)=> {
            this.eraseState(stateId);
        }, this);
        this._hp = this._hp.clamp(0, this.mhp);
        this._mp = this._mp.clamp(0, this.mmp);
        this._tp = this._tp.clamp(0, this.maxTp());
    };
    recoverAll(): void {
        this.clearStates();
        this._hp = this.mhp;
        this._mp = this.mmp;
    };
    hpRate(): number {
        return this.hp / this.mhp;
    };
    mpRate(): number {
        return this.mmp > 0 ? this.mp / this.mmp : 0;
    };
    tpRate(): number {
        return this.tp / this.maxTp();
    };
    hide(): void {
        this._hidden = true;
    };
    appear(): void {
        this._hidden = false;
    };
    isHidden(): boolean {
        return this._hidden;
    };
    isAppeared(): boolean {
        return !this.isHidden();
    };
    isDead(): boolean {
        return this.isAppeared() && this.isDeathStateAffected();
    };
    isAlive(): boolean {
        return this.isAppeared() && !this.isDeathStateAffected();
    };
    isDying(): boolean {
        return this.isAlive() && this._hp < this.mhp / 4;
    };
    isRestricted(): boolean {
        return this.isAppeared() && this.restriction() > 0;
    };
    canInput(): boolean {
        return this.isAppeared() && !this.isRestricted() && !this.isAutoBattle();
    };
    canMove(): boolean {
        return this.isAppeared() && this.restriction() < 4;
    };
    isConfused(): boolean {
        return this.isAppeared() && this.restriction() >= 1 && this.restriction() <= 3;
    };
    confusionLevel(): number {
        return this.isConfused() ? this.restriction() : 0;
    };
    isActor(): boolean {
        return false;
    };
    isEnemy(): boolean {
        return false;
    };
    sortStates(): void {
        this._states.sort(function(a, b) {
            var p1 = $dataStates[a].priority;
            var p2 = $dataStates[b].priority;
            if (p1 !== p2) {
                return p2 - p1;
            }
            return a - b;
        });
    };
    restriction(): number {
        return Math.max.apply(null, this.states().map(function(state) {
            return state.restriction;
        }).concat(0));
    };
    addNewState(stateId: number): void {
        if (stateId === this.deathStateId()) {
            this.die();
        }
        var restricted = this.isRestricted();
        this._states.push(stateId);
        this.sortStates();
        if (!restricted && this.isRestricted()) {
            this.onRestrict();
        }
    };
    onRestrict(): void {
    };
    mostImportantStateText(): string {
        var states = this.states();
        for (var i = 0; i < states.length; i++) {
            if (states[i].message3) {
                return states[i].message3;
            }
        }
        return '';
    };
    stateMotionIndex(): number {
        var states = this.states();
        if (states.length > 0) {
            return states[0].motion;
        } else {
            return 0;
        }
    };
    stateOverlayIndex(): number {
        var states = this.states();
        if (states.length > 0) {
            return states[0].overlay;
        } else {
            return 0;
        }
    };
    isSkillWtypeOk(skill: RPGMakerMV.DataSkill): boolean {
        return true;
    };
    skillMpCost(skill: RPGMakerMV.DataSkill): number|any {
        return Math.floor(skill.mpCost * this.mcr);
    };
    skillTpCost(skill: RPGMakerMV.DataSkill): number|any {
        return skill.tpCost;
    };
    canPaySkillCost(skill: RPGMakerMV.DataSkill): boolean {
        return this._tp >= this.skillTpCost(skill) && this._mp >= this.skillMpCost(skill);
    };
    paySkillCost(skill: RPGMakerMV.DataSkill): void {
        this._mp -= this.skillMpCost(skill);
        this._tp -= this.skillTpCost(skill);
    };
    isOccasionOk(item: RPGMakerMV.DataAnyItem|any): boolean {
        if ($gameParty.inBattle()) {
            return item.occasion === 0 || item.occasion === 1;
        } else {
            return item.occasion === 0 || item.occasion === 2;
        }
    };
    meetsUsableItemConditions(item: RPGMakerMV.DataAnyItem): boolean {
        return this.canMove() && this.isOccasionOk(item);
    };
    meetsSkillConditions(skill: RPGMakerMV.DataSkill|any): boolean {
        return (this.meetsUsableItemConditions(skill) &&
                this.isSkillWtypeOk(skill) && this.canPaySkillCost(skill) &&
                !this.isSkillSealed(skill.id) && !this.isSkillTypeSealed(skill.stypeId));
    };
    meetsItemConditions(item: RPGMakerMV.DataSkill|any): boolean {
        return this.meetsUsableItemConditions(item) && $gameParty.hasItem(item);
    };
    canUse(item: RPGMakerMV.DataAnyItem|any): boolean {
        if (!item) {
            return false;
        } else if (DataManager.isSkill(item)) {
            return this.meetsSkillConditions(item);
        } else if (DataManager.isItem(item)) {
            return this.meetsItemConditions(item);
        } else {
            return false;
        }
    };
    canEquip(item: RPGMakerMV.DataAnyItem): boolean {
        if (!item) {
            return false;
        } else if (DataManager.isWeapon(item)) {
            return this.canEquipWeapon(item);
        } else if (DataManager.isArmor(item)) {
            return this.canEquipArmor(item);
        } else {
            return false;
        }
    };
    canEquipWeapon(item: RPGMakerMV.DataWeapon): boolean {
        return this.isEquipWtypeOk(item.wtypeId) && !this.isEquipTypeSealed(item.etypeId);
    };
    canEquipArmor(item: RPGMakerMV.DataArmor): boolean {
        return this.isEquipAtypeOk(item.atypeId) && !this.isEquipTypeSealed(item.etypeId);
    };
    attackSkillId(): number {
        return 1;
    };
    guardSkillId(): number {
        return 2;
    };
    canAttack(): boolean {
        return this.canUse($dataSkills[this.attackSkillId()]);
    };
    canGuard(): boolean {
        return this.canUse($dataSkills[this.guardSkillId()]);
    };
}

//-----------------------------------------------------------------------------
// Game_Battler
//
// The superclass of Game_Actor and Game_Enemy. It contains methods for sprites
// and actions.
 
class Game_Battler extends Game_BattlerBase {
    //constructor() {
    //    super();
    //    this.initialize.apply(this, arguments);
    //}
    constructor(...args: any[]) {
        super(...args);
        this.initialize(...args);
    }
    initialize(...args: any[]): void {
        Game_BattlerBase.prototype.initialize.call(this);
    };
    initMembers(): void {
        Game_BattlerBase.prototype.initMembers.call(this);
        this._actions = [];
        this._speed = 0;
        this._result = new Game_ActionResult();
        this._actionState = '';
        this._lastTargetIndex = 0;
        this._animations = [];
        this._damagePopup = false;
        this._effectType = null;
        this._motionType = null;
        this._weaponImageId = 0;
        this._motionRefresh = false;
        this._selected = false;
    };
    _actions: Game_Action[];
    _speed: number;
    _result: Game_ActionResult;
    _actionState: string;
    _lastTargetIndex: number;
    _animations: RPGMakerMV.BattlerAnimation[];
    _damagePopup: boolean;
    _effectType: string;
    _motionType: string;
    _weaponImageId: number;
    _motionRefresh: boolean;
    _selected: boolean;

    clearAnimations(): void {
        this._animations = [];
    };
    clearDamagePopup(): void{
        this._damagePopup = false;
    };
    clearWeaponAnimation(): void {
        this._weaponImageId = 0;
    };
    clearEffect(): void {
        this._effectType = null;
    };
    clearMotion(): void {
        this._motionType = null;
        this._motionRefresh = false;
    };
    requestEffect(effectType: string): void {
        this._effectType = effectType;
    };
    requestMotion(motionType: string): void {
        this._motionType = motionType;
    };
    requestMotionRefresh(): void {
        this._motionRefresh = true;
    };
    select(): void {
        this._selected = true;
    };
    deselect(): void {
        this._selected = false;
    };
    isAnimationRequested(): boolean {
        return this._animations.length > 0;
    };
    isDamagePopupRequested(): boolean {
        return this._damagePopup;
    };
    isEffectRequested(): boolean {
        return !!this._effectType;
    };
    isMotionRequested(): boolean {
        return !!this._motionType;
    };
    isWeaponAnimationRequested(): boolean {
        return this._weaponImageId > 0;
    };
    isMotionRefreshRequested(): boolean {
        return this._motionRefresh;
    };
    isSelected(): boolean {
        return this._selected;
    };
    effectType(): string {
        return this._effectType;
    };
    motionType(): string {
        return this._motionType;
    };
    weaponImageId(): number {
        return this._weaponImageId;
    };
    shiftAnimation(): RPGMakerMV.BattlerAnimation {
        return this._animations.shift();
    };
    startAnimation(animationId: number, mirror: boolean, delay: number): void {
        var data:any = { animationId: animationId, mirror: mirror, delay: delay };
        this._animations.push(data);
    };
    startDamagePopup(): void {
        this._damagePopup = true;
    };
    startWeaponAnimation(weaponImageId: number): void {
        this._weaponImageId = weaponImageId;
    };
    action(index: number): Game_Action {
        return this._actions[index];
    };
    setAction(index: number, action: Game_Action): void {
        this._actions[index] = action;
    };
    numActions(): number {
        return this._actions.length;
    };
    clearActions(): void {
        this._actions = [];
    };
    result(): Game_ActionResult {
        return this._result;
    };
    clearResult(): void {
        this._result.clear();
    };
    refresh(): void {
        Game_BattlerBase.prototype.refresh.call(this);
        if (this.hp === 0) {
            this.addState(this.deathStateId());
        } else {
            this.removeState(this.deathStateId());
        }
    };
    addState(stateId: number): void {
        if (this.isStateAddable(stateId)) {
            if (!this.isStateAffected(stateId)) {
                this.addNewState(stateId);
                this.refresh();
            }
            this.resetStateCounts(stateId);
            this._result.pushAddedState(stateId);
        }
    };
    isStateAddable(stateId: number): boolean {
        return (this.isAlive() && $dataStates[stateId] &&
                !this.isStateResist(stateId) &&
                !this._result.isStateRemoved(stateId) &&
                !this.isStateRestrict(stateId));
    };
    isStateRestrict(stateId: number): boolean {
        return $dataStates[stateId].removeByRestriction && this.isRestricted();
    };
    onRestrict(): void {
        Game_BattlerBase.prototype.onRestrict.call(this);
        this.clearActions();
        this.states().forEach((state)=> {
            if (state.removeByRestriction) {
                this.removeState(state.id);
            }
        }, this);
    };
    removeState(stateId: number): void {
        if (this.isStateAffected(stateId)) {
            if (stateId === this.deathStateId()) {
                this.revive();
            }
            this.eraseState(stateId);
            this.refresh();
            this._result.pushRemovedState(stateId);
        }
    };
    escape(): void {
        if ($gameParty.inBattle()) {
            this.hide();
        }
        this.clearActions();
        this.clearStates();
        SoundManager.playEscape();
    };
    addBuff(paramId: number, turns: number): void {
        if (this.isAlive()) {
            this.increaseBuff(paramId);
            if (this.isBuffAffected(paramId)) {
                this.overwriteBuffTurns(paramId, turns);
            }
            this._result.pushAddedBuff(paramId);
            this.refresh();
        }
    };
    addDebuff(paramId: number, turns: number): void {
        if (this.isAlive()) {
            this.decreaseBuff(paramId);
            if (this.isDebuffAffected(paramId)) {
                this.overwriteBuffTurns(paramId, turns);
            }
            this._result.pushAddedDebuff(paramId);
            this.refresh();
        }
    };
    removeBuff(paramId: number): void {
        if (this.isAlive() && this.isBuffOrDebuffAffected(paramId)) {
            this.eraseBuff(paramId);
            this._result.pushRemovedBuff(paramId);
            this.refresh();
        }
    };
    removeBattleStates(): void {
        this.states().forEach((state)=> {
            if (state.removeAtBattleEnd) {
                this.removeState(state.id);
            }
        }, this);
    };
    removeAllBuffs(): void {
        for (var i = 0; i < this.buffLength(); i++) {
            this.removeBuff(i);
        }
    };
    removeStatesAuto(timing: number): void {
        this.states().forEach((state) =>{
            if (this.isStateExpired(state.id) && state.autoRemovalTiming === timing) {
                this.removeState(state.id);
            }
        }, this);
    };
    removeBuffsAuto(): void {
        for (var i = 0; i < this.buffLength(); i++) {
            if (this.isBuffExpired(i)) {
                this.removeBuff(i);
            }
        }
    };
    removeStatesByDamage(): void {
        this.states().forEach((state)=> {
            if (state.removeByDamage && Math.randomInt(100) < state.chanceByDamage) {
                this.removeState(state.id);
            }
        }, this);
    };
    makeActionTimes(): number {
        return this.actionPlusSet().reduce(function(r, p) {
            return Math.random() < p ? r + 1 : r;
        }, 1);
    };
    makeActions(): void {
        this.clearActions();
        if (this.canMove()) {
            var actionTimes = this.makeActionTimes();
            this._actions = [];
            for (var i = 0; i < actionTimes; i++) {
                this._actions.push(new Game_Action(this));
            }
        }
    };
    speed(): number {
        return this._speed;
    };
    makeSpeed(): void {
        this._speed = Math.min.apply(null, this._actions.map(function(action) {
            return action.speed();
        })) || 0;
    };
    currentAction(): Game_Action {
        return this._actions[0];
    };
    removeCurrentAction(): void {
        this._actions.shift();
    };
    setLastTarnget(target: Game_Battler|any): void {
        if (target) {
            this._lastTargetIndex = target.index();
        } else {
            this._lastTargetIndex = 0;
        }
    };
    forceAction(skillId: number, targetIndex: number): void {
        this.clearActions();
        var action = new Game_Action(this, true);
        action.setSkill(skillId);
        if (targetIndex === -2) {
            action.setTarget(this._lastTargetIndex);
        } else if (targetIndex === -1) {
            action.decideRandomTarget();
        } else {
            action.setTarget(targetIndex);
        }
        this._actions.push(action);
    };
    useItem(item: RPGMakerMV.DataAnyItem|any): void {
        if (DataManager.isSkill(item)) {
            this.paySkillCost(item);
        } else if (DataManager.isItem(item)) {
            this.consumeItem(item);
        }
    };
    consumeItem(item: RPGMakerMV.DataAnyItem): void {
        $gameParty.consumeItem(item);
    };
    gainHp(value: number): void {
        this._result.hpDamage = -value;
        this._result.hpAffected = true;
        this.setHp(this.hp + value);
    };
    gainMp(value: number): void {
        this._result.mpDamage = -value;
        this.setMp(this.mp + value);
    };
    gainTp(value: number): void {
        this._result.tpDamage = -value;
        this.setTp(this.tp + value);
    };
    gainSilentTp(value: number): void {
        this.setTp(this.tp + value);
    };
    initTp(): void {
        this.setTp(Math.randomInt(25));
    };
    clearTp(): void {
        this.setTp(0);
    };    
    chargeTpByDamage(damageRate: number): void {
        var value = Math.floor(50 * damageRate * this.tcr);
        this.gainSilentTp(value);
    };
    regenerateHp(): void {
        var value = Math.floor(this.mhp * this.hrg);
        value = Math.max(value, -this.maxSlipDamage());
        if (value !== 0) {
            this.gainHp(value);
        }
    };
    maxSlipDamage(): number {
        return $dataSystem.optSlipDeath ? this.hp : Math.max(this.hp - 1, 0);
    };
    regenerateMp(): void {
        var value = Math.floor(this.mmp * this.mrg);
        if (value !== 0) {
            this.gainMp(value);
        }
    };
    regenerateTp(): void {
        var value = Math.floor(100 * this.trg);
        this.gainSilentTp(value);
    };
    regenerateAll(): void {
        if (this.isAlive()) {
            this.regenerateHp();
            this.regenerateMp();
            this.regenerateTp();
        }
    };
    onBattleStart(): void {
        this.setActionState('undecided');
        this.clearMotion();
        if (!this.isPreserveTp()) {
            this.initTp();
        }
    };
    onAllActionsEnd(): void {
        this.clearResult();
        this.removeStatesAuto(1);
        this.removeBuffsAuto();
    };
    onTurnEnd(): void {
        this.clearResult();
        this.regenerateAll();
        if (!BattleManager.isForcedTurn()) {
            this.updateStateTurns();
            this.updateBuffTurns();
        }
        this.removeStatesAuto(2);
    };
    onBattleEnd(): void {
        this.clearResult();
        this.removeBattleStates();
        this.removeAllBuffs();
        this.clearActions();
        if (!this.isPreserveTp()) {
            this.clearTp();
        }
        this.appear();
    };
    onDamage(value: number): void {
        this.removeStatesByDamage();
        this.chargeTpByDamage(value / this.mhp);
    };
    setActionState(actionState: string): void {
        this._actionState = actionState;
        this.requestMotionRefresh();
    };
    isUndecided(): boolean {
        return this._actionState === 'undecided';
    };
    isInputting(): boolean {
        return this._actionState === 'inputting';
    };
    isWaiting(): boolean {
        return this._actionState === 'waiting';
    };
    isActing(): boolean {
        return this._actionState === 'acting';
    };
    isChanting(): boolean {
        if (this.isWaiting()) {
            return this._actions.some(function(action) {
                return action.isMagicSkill();
            });
        }
        return false;
    };
    isGuardWaiting(): boolean {
        if (this.isWaiting()) {
            return this._actions.some(function(action) {
                return action.isGuard();
            });
        }
        return false;
    };
    performActionStart(action: Game_Action): void {
        if (!action.isGuard()) {
            this.setActionState('acting');
        }
    };
    performAction(action: Game_Action): void {
    };
    
    performActionEnd(): void {
        this.setActionState('done');
    };
    performDamage(): void {
    };
    performMiss(): void {
        SoundManager.playMiss();
    };
    performRecovery(): void {
        SoundManager.playRecovery();
    };
    performEvasion(): void {
        SoundManager.playEvasion();
    };
    performMagicEvasion(): void {
        SoundManager.playMagicEvasion();
    };
    performCounter(): void {
        SoundManager.playEvasion();
    };
    performReflection(): void {
        SoundManager.playReflection();
    };
    performSubstitute(target: Game_Battler): void {
    };
    performCollapse(): void {
    };
}
//Game_Battler.prototype = Object.create(Game_BattlerBase.prototype);
//Game_Battler.prototype.constructor = Game_Battler;

//-----------------------------------------------------------------------------
// Game_Actor
//
// The game object class for an actor.
class Game_Actor extends Game_Battler 
{
    //constructor() {
    //    super();
    //    this.initialize.apply(this, arguments);
    //}

    constructor(...args: [number] ){
        super(...args);
        this.initialize(...args);
    }
          
    public get level() :number{
        return this._level;
    }
    
    _actorId: number ;
    _name: string ;
    _nickname: string ;
    _classId: number;
    _level: number;
    _characterName: string ;
    _characterIndex: number;
    _faceName: string ;
    _faceIndex: number;
    _battlerName: string ;
    _exp: { [key: number]: number };

    _skills: number[];
    _equips: Game_Item[];
    _actionInputIndex: number;
    _lastMenuSkill: Game_Item|any ;
    _lastBattleSkill: Game_Item|any;
    _lastCommandSymbol: string;
    
    _profile: string;
    _stateSteps: { [key: number]: number };

    initialize(actorId?: number): void {
        Game_Battler.prototype.initialize.call(this);
        this.setup(actorId);
    };
    initMembers(): void {
        Game_Battler.prototype.initMembers.call(this);
        this._actorId = 0;
        this._name = '';
        this._nickname = '';
        this._classId = 0;
        this._level = 0;
        this._characterName = '';
        this._characterIndex = 0;
        this._faceName = '';
        this._faceIndex = 0;
        this._battlerName = '';
        this._exp = {};
        this._skills = [];
        this._equips = [];
        this._actionInputIndex = 0;
        this._lastMenuSkill = new Game_Item();
        this._lastBattleSkill  = new Game_Item();
        this._lastCommandSymbol = '';
    };
    setup(actorId: number): void {
        var actor = $dataActors[actorId];
        this._actorId = actorId;
        this._name = actor.name;
        this._nickname = actor.nickname;
        this._profile = actor.profile;
        this._classId = actor.classId;
        this._level = actor.initialLevel;
        this.initImages();
        this.initExp();
        this.initSkills();
        this.initEquips(actor.equips);
        this.clearParamPlus();
        this.recoverAll();
    };
    actorId(): number {
        return this._actorId;
    };
    actor(): RPGMakerMV.DataActor {
        return $dataActors[this._actorId];
    };
    name(): string {
        return this._name;
    };
    setName(name: string): void {
        this._name = name;
    };
    nickname(): string {
        return this._nickname;
    };
    setNickname(nickname: string): void {
        this._nickname = nickname;
    };
    profile(): string {
        return this._profile;
    };
    setProfile(profile: string): void {
        this._profile = profile;
    };
    characterName(): string {
        return this._characterName;
    };
    characterIndex(): number {
        return this._characterIndex;
    };
    faceName(): string {
        return this._faceName;
    };
    faceIndex(): number {
        return this._faceIndex;
    };
    battlerName(): string {
        return this._battlerName;
    };

    clearStates(): void {
        Game_Battler.prototype.clearStates.call(this);
        this._stateSteps = {};
    };
    eraseState(stateId: number): void {
        Game_Battler.prototype.eraseState.call(this, stateId);
        delete this._stateSteps[stateId];
    };
    resetStateCounts(stateId: number): void {
        Game_Battler.prototype.resetStateCounts.call(this, stateId);
        this._stateSteps[stateId] = $dataStates[stateId].stepsToRemove;
    };
    initImages(): void {
        var actor = this.actor();
        this._characterName = actor.characterName;
        this._characterIndex = actor.characterIndex;
        this._faceName = actor.faceName;
        this._faceIndex = actor.faceIndex;
        this._battlerName = actor.battlerName;
    };
    expForLevel(level: number): number {
        var c = this.currentClass();
        var basis = c.expParams[0];
        var extra = c.expParams[1];
        var acc_a = c.expParams[2];
        var acc_b = c.expParams[3];
        return Math.round(basis*(Math.pow(level-1, 0.9+acc_a/250))*level*
                (level+1)/(6+Math.pow(level,2)/50/acc_b)+(level-1)*extra);
    };
    initExp(): void {
        this._exp[this._classId] = this.currentLevelExp();
    };
    currentExp(): number {
        return this._exp[this._classId];
    };
    currentLevelExp(): number {
        return this.expForLevel(this._level);
    };
    nextLevelExp(): number {
        return this.expForLevel(this._level + 1);
    };
    nextRequiredExp(): number {
        return this.nextLevelExp() - this.currentExp();
    };
    maxLevel(): number {
        return this.actor().maxLevel;
    };
    isMaxLevel(): boolean {
        return this._level >= this.maxLevel();
    };
    initSkills(): void {
        this._skills = [];
        this.currentClass().learnings.forEach((learning)=> {
            if (learning.level <= this._level) {
                this.learnSkill(learning.skillId);
            }
        }, this);
    };
    initEquips(equips: number[]): void {
        var slots = this.equipSlots();
        var maxSlots = slots.length;
        this._equips = [];
        for (var i = 0; i < maxSlots; i++) {
            this._equips[i] = new Game_Item();
        }
        for (var j = 0; j < equips.length; j++) {
            if (j < maxSlots) {
                this._equips[j].setEquip(slots[j] === 1, equips[j]);
            }
        }
        this.releaseUnequippableItems(true);
        this.refresh();
    };
    equipSlots(): number[] {
        var slots = [];
        for (var i = 1; i < $dataSystem.equipTypes.length; i++) {
            slots.push(i);
        }
        if (slots.length >= 2 && this.isDualWield()) {
            slots[1] = 1;
        }
        return slots;
    };
    equips(): Game_Item[]|any {
        return this._equips.map(function(item) {
            return item.object();
        });
    };
    weapons(): RPGMakerMV.DataWeapon[] {
        return this.equips().filter((item:any)=> {
            return item && DataManager.isWeapon(item);
        });
    };
    armors(): RPGMakerMV.DataArmor[] {
        return this.equips().filter((item:any)=> {
            return item && DataManager.isArmor(item);
        });
    };
    hasWeapon(weapon: RPGMakerMV.DataWeapon): boolean {
        return this.weapons().contains(weapon);
    };
    hasArmor(armor: RPGMakerMV.DataArmor): boolean {
        return this.armors().contains(armor);
    };
    
    isEquipChangeOk(slotId: number): boolean {
        return (!this.isEquipTypeLocked(this.equipSlots()[slotId]) &&
                !this.isEquipTypeSealed(this.equipSlots()[slotId]));
    };
    changeEquip(slotId: number, item: RPGMakerMV.DataWeapon | RPGMakerMV.DataArmor|any): void {
        if (this.tradeItemWithParty(item, this.equips()[slotId]) &&
                (!item || this.equipSlots()[slotId] === item.etypeId)) {
            this._equips[slotId].setObject(item);
            this.refresh();
        }
    };
    forceChangeEquip(slotId: number, item: RPGMakerMV.DataWeapon | RPGMakerMV.DataArmor): void {
        this._equips[slotId].setObject(item);
        this.releaseUnequippableItems(true);
        this.refresh();
    };
    tradeItemWithParty(newItem: RPGMakerMV.DataWeapon | RPGMakerMV.DataArmor, oldItem: RPGMakerMV.DataWeapon | RPGMakerMV.DataArmor): boolean {
        if (newItem && !$gameParty.hasItem(newItem)) {
            return false;
        } else {
            $gameParty.gainItem(oldItem, 1);
            $gameParty.loseItem(newItem, 1);
            return true;
        }
    };
    changeEquipById(etypeId: number, itemId: number): void {
        var slotId = etypeId - 1;
        if (this.equipSlots()[slotId] === 1) {
            this.changeEquip(slotId, $dataWeapons[itemId]);
        } else {
            this.changeEquip(slotId, $dataArmors[itemId]);
        }
    };
    isEquipped(item: RPGMakerMV.DataAnyItem|any): boolean {
        return this.equips().contains(item);
    };
    discardEquip(item: RPGMakerMV.DataWeapon | RPGMakerMV.DataArmor|any): void {
        var slotId = this.equips().indexOf(item);
        if (slotId >= 0) {
            this._equips[slotId].setObject(null);
        }
    };
    releaseUnequippableItems(forcing: boolean): void {
        for (;;) {
            var slots = this.equipSlots();
            var equips = this.equips();
            var changed = false;
            for (var i = 0; i < equips.length; i++) {
                var item:any = equips[i];
                if (item && (!this.canEquip(item) || item.etypeId !== slots[i])) {
                    if (!forcing) {
                        this.tradeItemWithParty(null, item);
                    }
                    this._equips[i].setObject(null);
                    changed = true;
                }
            }
            if (!changed) {
                break;
            }
        }
    };
    clearEquipments(): void {
        var maxSlots = this.equipSlots().length;
        for (var i = 0; i < maxSlots; i++) {
            if (this.isEquipChangeOk(i)) {
                this.changeEquip(i, null);
            }
        }
    };
    optimizeEquipments(): void {
        var maxSlots = this.equipSlots().length;
        this.clearEquipments();
        for (var i = 0; i < maxSlots; i++) {
            if (this.isEquipChangeOk(i)) {
                this.changeEquip(i, this.bestEquipItem(i));
            }
        }
    };
    bestEquipItem(slotId: number): RPGMakerMV.DataWeapon | RPGMakerMV.DataArmor {
        var etypeId = this.equipSlots()[slotId];
        var items = $gameParty.equipItems().filter((item:any)=> {
            return item.etypeId === etypeId && this.canEquip(item);
        }, this);
        var bestItem = null;
        var bestPerformance = -1000;
        for (var i = 0; i < items.length; i++) {
            var performance = this.calcEquipItemPerformance(items[i]);
            if (performance > bestPerformance) {
                bestPerformance = performance;
                bestItem = items[i];
            }
        }
        return bestItem;
    };
    calcEquipItemPerformance(item: RPGMakerMV.DataWeapon | RPGMakerMV.DataArmor): number {
        return item.params.reduce(function(a, b) {
            return a + b;
        });
    };
    isSkillWtypeOk(skill: RPGMakerMV.DataSkill): boolean {
        var wtypeId1 = skill.requiredWtypeId1;
        var wtypeId2 = skill.requiredWtypeId2;
        if ((wtypeId1 === 0 && wtypeId2 === 0) ||
                (wtypeId1 > 0 && this.isWtypeEquipped(wtypeId1)) ||
                (wtypeId2 > 0 && this.isWtypeEquipped(wtypeId2))) {
            return true;
        } else {
            return false;
        }
    };
    isWtypeEquipped(wtypeId: number): boolean {
        return this.weapons().some(function(weapon) {
            return weapon.wtypeId === wtypeId;
        });
    };
    refresh(): void {
        this.releaseUnequippableItems(false);
        Game_Battler.prototype.refresh.call(this);
    };
    isActor(): boolean {
        return true;
    };
    friendsUnit(): Game_Party {
        return $gameParty;
    };
    opponentsUnit(): Game_Troop {
        return $gameTroop;
    };
    index(): number {
        return $gameParty.members().indexOf(this);
    };
    isBattleMember(): boolean {
        return $gameParty.battleMembers().contains(this);
    };
    isFormationChangeOk(): boolean {
        return true;
    };
    currentClass(): RPGMakerMV.DataClass {
        return $dataClasses[this._classId];
    };
    isClass(gameClass: RPGMakerMV.DataClass): boolean {
        return gameClass && this._classId === gameClass.id;
    };
    skills(): RPGMakerMV.DataSkill[] {
        var list:any = [];
        this._skills.concat(this.addedSkills()).forEach(function(id) {
            if (!list.contains($dataSkills[id])) {
                list.push($dataSkills[id]);
            }
        });
        return list;
    };
    usableSkills(): RPGMakerMV.DataSkill[] {
        return this.skills().filter((skill)=> {
            return this.canUse(skill);
        }, this);
    };
    traitObjects(): RPGMakerMV.DataState[] {
        var objects = Game_Battler.prototype.traitObjects.call(this);
        objects = objects.concat([this.actor(), this.currentClass()]);
        var equips = this.equips();
        for (var i = 0; i < equips.length; i++) {
            var item = equips[i];
            if (item) {
                objects.push(item);
            }
        }
        return objects;
    };
    attackElements(): number[] {
        var set = Game_Battler.prototype.attackElements.call(this);
        if (this.hasNoWeapons() && !set.contains(this.bareHandsElementId())) {
            set.push(this.bareHandsElementId());
        }
        return set;
    };
    hasNoWeapons(): boolean {
        return this.weapons().length === 0;
    };
    bareHandsElementId(): number {
        return 1;
    };
    paramMax(paramId: number): number {
        if (paramId === 0) {
            return 9999;    // MHP
        }
        return Game_Battler.prototype.paramMax.call(this, paramId);
    };
    paramBase(paramId: number): number {
        return this.currentClass().params[paramId][this._level];
    };
    paramPlus(paramId: number): number {
        var value = Game_Battler.prototype.paramPlus.call(this, paramId);
        var equips = this.equips();
        for (var i = 0; i < equips.length; i++) {
            var item:any = equips[i];
            if (item) {
                value += item.params[paramId];
            }
        }
        return value;
    };
    attackAnimationId1(): number {
        if (this.hasNoWeapons()) {
            return this.bareHandsAnimationId();
        } else {
            var weapons = this.weapons();
            return weapons[0] ? weapons[0].animationId : 0;
        }
    };
    attackAnimationId2(): number {
        var weapons = this.weapons();
        return weapons[1] ? weapons[1].animationId : 0;
    };
    bareHandsAnimationId(): number {
        return 1;
    };
    changeExp(exp: number, show: boolean): void {
        this._exp[this._classId] = Math.max(exp, 0);
        var lastLevel = this._level;
        var lastSkills = this.skills();
        while (!this.isMaxLevel() && this.currentExp() >= this.nextLevelExp()) {
            this.levelUp();
        }
        while (this.currentExp() < this.currentLevelExp()) {
            this.levelDown();
        }
        if (show && this._level > lastLevel) {
            this.displayLevelUp(this.findNewSkills(lastSkills));
        }
        this.refresh();
    };
    levelUp(): void {
        this._level++;
        this.currentClass().learnings.forEach((learning)=> {
            if (learning.level === this._level) {
                this.learnSkill(learning.skillId);
            }
        }, this);
    };
    levelDown(): void {
        this._level--;
    };
    findNewSkills(lastSkills: RPGMakerMV.DataSkill[]): RPGMakerMV.DataSkill[] {
        var newSkills = this.skills();
        for (var i = 0; i < lastSkills.length; i++) {
            var index = newSkills.indexOf(lastSkills[i]);
            if (index >= 0) {
                newSkills.splice(index, 1);
            }
        }
        return newSkills;
    };
    displayLevelUp(newSkills: RPGMakerMV.DataSkill[]): void {
        var text = TextManager.levelUp.format(this._name, TextManager.level, this._level);
        $gameMessage.newPage();
        $gameMessage.add(text);
        newSkills.forEach(function(skill) {
            $gameMessage.add(TextManager.obtainSkill.format(skill.name));
        });
    };
    gainExp(exp: number): void {
        var newExp = this.currentExp() + Math.round(exp * this.finalExpRate());
        this.changeExp(newExp, this.shouldDisplayLevelUp());
    };
    finalExpRate(): number {
        return this.exr * (this.isBattleMember() ? 1 : this.benchMembersExpRate());
    };
    benchMembersExpRate(): number {
        return $dataSystem.optExtraExp ? 1 : 0;
    };
    shouldDisplayLevelUp(): boolean {
        return true;
    };
    changeLevel(level: number, show: boolean): void {
        level = level.clamp(1, this.maxLevel());
        this.changeExp(this.expForLevel(level), show);
    };
    learnSkill(skillId: number): void {
        if (!this.isLearnedSkill(skillId)) {
            this._skills.push(skillId);
            this._skills.sort(function(a, b) {
                return a - b;
            });
        }
    };
    forgetSkill(skillId: number): void {
        var index = this._skills.indexOf(skillId);
        if (index >= 0) {
            this._skills.splice(index, 1);
        }
    };
    isLearnedSkill(skillId: number): boolean {
        return this._skills.contains(skillId);
    };
    hasSkill(skillId: number): boolean {
        return this.skills().contains($dataSkills[skillId]);
    };
    changeClass(classId: number, keepExp: number): void {
        if (keepExp) {
            this._exp[classId] = this.currentExp();
        }
        this._classId = classId;
        this.changeExp(this._exp[this._classId] || 0, false);
        this.refresh();
    };
    setCharacterImage(characterName: string, characterIndex: number): void {
        this._characterName = characterName;
        this._characterIndex = characterIndex;
    };
    setFaceImage(faceName: string, faceIndex: number): void {
        this._faceName = faceName;
        this._faceIndex = faceIndex;
    };
    setBattlerImage(battlerName: string): void {
        this._battlerName = battlerName;
    };
    isSpriteVisible(): boolean {
        return $gameSystem.isSideView();
    };
    startAnimation(animationId: number, mirror: boolean, delay: number): void {
        mirror = !mirror;
        Game_Battler.prototype.startAnimation.call(this, animationId, mirror, delay);
    };
    performActionStart(action: Game_Action): void {
        Game_Battler.prototype.performActionStart.call(this, action);
    };
    performAction(action: Game_Action): void {
        Game_Battler.prototype.performAction.call(this, action);
        if (action.isAttack()) {
            this.performAttack();
        } else if (action.isGuard()) {
            this.requestMotion('guard');
        } else if (action.isMagicSkill()) {
            this.requestMotion('spell');
        } else if (action.isSkill()) {
            this.requestMotion('skill');
        } else if (action.isItem()) {
            this.requestMotion('item');
        }
    };
    performActionEnd(): void {
        Game_Battler.prototype.performActionEnd.call(this);
    };
    performAttack(): void {
        var weapons = this.weapons();
        var wtypeId = weapons[0] ? weapons[0].wtypeId : 0;
        var attackMotion = $dataSystem.attackMotions[wtypeId];
        if (attackMotion) {
            if (attackMotion.type === 0) {
                this.requestMotion('thrust');
            } else if (attackMotion.type === 1) {
                this.requestMotion('swing');
            } else if (attackMotion.type === 2) {
                this.requestMotion('missile');
            }
            this.startWeaponAnimation(attackMotion.weaponImageId);
        }
    };
    performDamage(): void {
        Game_Battler.prototype.performDamage.call(this);
        if (this.isSpriteVisible()) {
            this.requestMotion('damage');
        } else {
            $gameScreen.startShake(5, 5, 10);
        }
        SoundManager.playActorDamage();
    };
    performEvasion(): void {
        Game_Battler.prototype.performEvasion.call(this);
        this.requestMotion('evade');
    };
    performMagicEvasion(): void {
        Game_Battler.prototype.performMagicEvasion.call(this);
        this.requestMotion('evade');
    };
    performCounter(): void {
        Game_Battler.prototype.performCounter.call(this);
        this.performAttack();
    };
    performCollapse(): void {
        Game_Battler.prototype.performCollapse.call(this);
        if ($gameParty.inBattle()) {
            SoundManager.playActorCollapse();
        }
    };
    performVictory(): void {
        if (this.canMove()) {
            this.requestMotion('victory');
        }
    };
    performEscape(): void {
        if (this.canMove()) {
            this.requestMotion('escape');
        }
    };
    makeActionList(): Game_Action[] {
        var list = [];
        var action = new Game_Action(this);
        action.setAttack();
        list.push(action);
        this.usableSkills().forEach((skill)=> {
            action = new Game_Action(this);
            action.setSkill(skill.id);
            list.push(action);
        }, this);
        return list;
    };
    makeAutoBattleActions(): void {
        for (var i = 0; i < this.numActions(); i++) {
            var list = this.makeActionList();
            var maxValue = Number.MIN_VALUE;
            for (var j = 0; j < list.length; j++) {
                var value = list[j].evaluate();
                if (value > maxValue) {
                    maxValue = value;
                    this.setAction(i, list[j]);
                }
            }
        }
        this.setActionState('waiting');
    };
    makeConfusionActions(): void {
        for (var i = 0; i < this.numActions(); i++) {
            this.action(i).setConfusion();
        }
        this.setActionState('waiting');
    };
    makeActions(): void {
        Game_Battler.prototype.makeActions.call(this);
        if (this.numActions() > 0) {
            this.setActionState('undecided');
        } else {
            this.setActionState('waiting');
        }
        if (this.isAutoBattle()) {
            this.makeAutoBattleActions();
        } else if (this.isConfused()) {
            this.makeConfusionActions();
        }
    };
    onPlayerWalk(): void {
        this.clearResult();
        this.checkFloorEffect();
        if ($gamePlayer.isNormal()) {
            this.turnEndOnMap();
            this.states().forEach((state)=> {
                this.updateStateSteps(state);
            }, this);
            this.showAddedStates();
            this.showRemovedStates();
        }
    };
    updateStateSteps(state: RPGMakerMV.DataState): void {
        if (state.removeByWalking) {
            if (this._stateSteps[state.id] > 0) {
                if (--this._stateSteps[state.id] === 0) {
                    this.removeState(state.id);
                }
            }
        }
    };
    showAddedStates(): void {
        this.result().addedStateObjects().forEach((state)=>{
            if (state.message1) {
                $gameMessage.add(this._name + state.message1);
            }
        }, this);
    };
    showRemovedStates(): void {
        this.result().removedStateObjects().forEach((state)=> {
            if (state.message4) {
                $gameMessage.add(this._name + state.message4);
            }
        }, this);
    };
    stepsForTurn(): number {
        return 20;
    };
    turnEndOnMap(): void {
        if ($gameParty.steps() % this.stepsForTurn() === 0) {
            this.onTurnEnd();
            if (this.result().hpDamage > 0) {
                this.performMapDamage();
            }
        }
    };
    checkFloorEffect(): void {
        if ($gamePlayer.isOnDamageFloor()) {
            this.executeFloorDamage();
        }
    };
    executeFloorDamage(): void {
        var damage = Math.floor(this.basicFloorDamage() * this.fdr);
        damage = Math.min(damage, this.maxFloorDamage());
        this.gainHp(-damage);
        if (damage > 0) {
            this.performMapDamage();
        }
    };
    basicFloorDamage(): number {
        return 10;
    };
    maxFloorDamage(): number {
        return $dataSystem.optFloorDeath ? this.hp : Math.max(this.hp - 1, 0);
    };
    performMapDamage(): void {
        if (!$gameParty.inBattle()) {
            $gameScreen.startFlashForDamage();
        }
    };
    clearActions(): void {
        Game_Battler.prototype.clearActions.call(this);
        this._actionInputIndex = 0;
    };
    inputtingAction(): Game_Action {
        return this.action(this._actionInputIndex);
    };
    selectNextCommand(): boolean {
        if (this._actionInputIndex < this.numActions() - 1) {
            this._actionInputIndex++;
            return true;
        } else {
            return false;
        }
    };
    selectPreviousCommand(): boolean {
        if (this._actionInputIndex > 0) {
            this._actionInputIndex--;
            return true;
        } else {
            return false;
        }
    };
    lastMenuSkill(): RPGMakerMV.DataSkill {
        return this._lastMenuSkill.object();
    };
    setLastMenuSkill(skill: RPGMakerMV.DataSkill|any): void {
        this._lastMenuSkill.setObject(skill);
    };
    lastBattleSkill(): RPGMakerMV.DataSkill {
        return this._lastBattleSkill.object();
    };
    setLastBattleSkill(skill: RPGMakerMV.DataSkill): void {
        this._lastBattleSkill.setObject(skill);
    };
    lastCommandSymbol(): string {
        return this._lastCommandSymbol;
    };
    setLastCommandSymbol(symbol: string): void {
        this._lastCommandSymbol = symbol;
    };
    testEscape(item: RPGMakerMV.DataAnyItem|any): boolean {
        return item.effects.some((effect:any, index:any, ar:any)=> {
            return effect && effect.code === Game_Action.EFFECT_SPECIAL;
        });
    };
    meetsUsableItemConditions(item: RPGMakerMV.DataAnyItem): boolean {
        if ($gameParty.inBattle() && !BattleManager.canEscape() && this.testEscape(item)) {
            return false;
        }
        return Game_BattlerBase.prototype.meetsUsableItemConditions.call(this, item);
    };
}
//Game_Actor.prototype = Object.create(Game_Battler.prototype);
//Game_Actor.prototype.constructor = Game_Actor;

//-----------------------------------------------------------------------------
// Game_Enemy
//
// The game object class for an enemy.

class Game_Enemy extends Game_Battler {

    //constructor(){
    //   super();
    //    this.initialize.apply(this, arguments);
    //};

    constructor(...args:[number,number,number]) {
        super(...args);
        this.initialize(...args);
    }

    initialize(enemyId: number, x: number, y: number): void {
        Game_Battler.prototype.initialize.call(this);
        this.setup(enemyId, x, y);
    };

    initMembers(): void {
        Game_Battler.prototype.initMembers.call(this);
        this._enemyId = 0;
        this._letter = '';
        this._plural = false;
        this._screenX = 0;
        this._screenY = 0;
    };



    setup(enemyId: number, x: number, y: number): void {
        this._enemyId = enemyId;
        this._screenX = x;
        this._screenY = y;
        this.recoverAll();
    };
    isEnemy(): boolean {
        return true;
    };
    friendsUnit(): Game_Troop {
        return $gameTroop;
    };
    opponentsUnit(): Game_Party {
        return $gameParty;
    };
    index(): number {
        return $gameTroop.members().indexOf(this);
    };
    isBattleMember(): boolean {
        return this.index() >= 0;
    };
    enemyId(): number {
        return this._enemyId;
    };
    enemy(): RPGMakerMV.DataEnemy {
        return $dataEnemies[this._enemyId];
    };
    traitObjects(): RPGMakerMV.DataState[] {
        return Game_Battler.prototype.traitObjects.call(this).concat(this.enemy());
    };
    paramBase(paramId: number): number {
        return this.enemy().params[paramId];
    };
    exp(): number {
        return this.enemy().exp;
    };
    gold(): number {
        return this.enemy().gold;
    };
    makeDropItems(): RPGMakerMV.DataAnyItem[] {
        return this.enemy().dropItems.reduce(function(this:any, r:any, di:any) {
            if (di.kind > 0 && Math.random() * di.denominator < this.dropItemRate()) {
                return r.concat(this.itemObject(di.kind, di.dataId));
            } else {
                return r;
            }
        }.bind(this), []);
    };

    dropItemRate(): number {
        return $gameParty.hasDropItemDouble() ? 2 : 1;
    };
    itemObject(kind: number, dataId: number): RPGMakerMV.DataAnyItem {
        if (kind === 1) {
            return $dataItems[dataId];
        } else if (kind === 2) {
            return $dataWeapons[dataId];
        } else if (kind === 3) {
            return $dataArmors[dataId];
        } else {
            return null;
        }
    };
    isSpriteVisible(): boolean {
        return true;
    };
    screenX(): number {
        return this._screenX;
    };
    screenY(): number {
        return this._screenY;
    };
    battlerName(): string {
        return this.enemy().battlerName;
    };
    battlerHue(): number {
        return this.enemy().battlerHue;
    };
    originalName(): string{
        return this.enemy().name;
    };
    name(): string{
        return this.originalName() + (this._plural ? this._letter : '');
    };
    isLetterEmpty(): any{
        return this._letter === '';
    };
    setLetter(letter: string): void {
        this._letter = letter;
    };
    setPlural(plural: any): void {
        this._plural = plural;
    };
    performActionStart(action: Game_Action): void {
        Game_Battler.prototype.performActionStart.call(this, action);
        this.requestEffect('whiten');
    };
    performAction(action: Game_Action): void {
        Game_Battler.prototype.performAction.call(this, action);
    };
    performActionEnd(): void {
        Game_Battler.prototype.performActionEnd.call(this);
    };
    performDamage(): void {
        Game_Battler.prototype.performDamage.call(this);
        SoundManager.playEnemyDamage();
        this.requestEffect('blink');
    };
    performCollapse(): void {
        Game_Battler.prototype.performCollapse.call(this);
        switch (this.collapseType()) {
        case 0:
            this.requestEffect('collapse');
            SoundManager.playEnemyCollapse();
            break;
        case 1:
            this.requestEffect('bossCollapse');
            SoundManager.playBossCollapse1();
            break;
        case 2:
            this.requestEffect('instantCollapse');
            break;
        }
    };
    transform(enemyId: number): void {
        var name = this.originalName();
        this._enemyId = enemyId;
        if (this.originalName() !== name) {
            this._letter = '';
            this._plural = false;
        }
        this.refresh();
        if (this.numActions() > 0) {
            this.makeActions();
        }
    };
    meetsCondition(action: RPGMakerMV.Action): boolean {
        var param1 = action.conditionParam1;
        var param2 = action.conditionParam2;
        switch (action.conditionType) {
        case 1:
            return this.meetsTurnCondition(param1, param2);
        case 2:
            return this.meetsHpCondition(param1, param2);
        case 3:
            return this.meetsMpCondition(param1, param2);
        case 4:
            return this.meetsStateCondition(param1);
        case 5:
            return this.meetsPartyLevelCondition(param1);
        case 6:
            return this.meetsSwitchCondition(param1);
        default:
            return true;
        }
    };
    meetsTurnCondition(param1: number, param2: number): boolean {
        var n = $gameTroop.turnCount();
        if (param2 === 0) {
            return n === param1;
        } else {
            return n > 0 && n >= param1 && n % param2 === param1 % param2;
        }
    };
    meetsHpCondition(param1: number, param2: number): boolean {
        return this.hpRate() >= param1 && this.hpRate() <= param2;
    };
    meetsMpCondition(param1: number, param2: number): boolean {
        return this.mpRate() >= param1 && this.mpRate() <= param2;
    };
    meetsStateCondition(param: number): boolean {
        return this.isStateAffected(param);
    };
    meetsPartyLevelCondition(param: number): boolean {
        return $gameParty.highestLevel() >= param;
    };
    meetsSwitchCondition(param: number): boolean {
        return $gameSwitches.value(param);
    };
    isActionValid(action: RPGMakerMV.Action): boolean {
        return this.meetsCondition(action) && this.canUse($dataSkills[action.skillId]);
    };
    selectAction(actionList: RPGMakerMV.Action[], ratingZero: number): RPGMakerMV.Action {
        var sum = actionList.reduce(function(r, a) {
            return r + a.rating - ratingZero;
        }, 0);
        if (sum > 0) {
            var value = Math.randomInt(sum);
            for (var i = 0; i < actionList.length; i++) {
                var action = actionList[i];
                value -= action.rating - ratingZero;
                if (value < 0) {
                    return action;
                }
            }
        } else {
            return null;
        }
    };
    selectAllActions(actionList: RPGMakerMV.Action[]): void {
        var ratingMax = Math.max.apply(null, actionList.map(function(a) {
            return a.rating;
        }));
        var ratingZero = ratingMax - 3;
        actionList = actionList.filter(function(a) {
            return a.rating > ratingZero;
        });
        for (var i = 0; i < this.numActions(); i++) {
            this.action(i).setEnemyAction(this.selectAction(actionList, ratingZero));
        }
    };
    makeActions(): void {
        Game_Battler.prototype.makeActions.call(this);
        if (this.numActions() > 0) {
            var actionList = this.enemy().actions.filter(function(this:any,a) {
                return this.isActionValid(a);
            }, this);
            if (actionList.length > 0) {
                this.selectAllActions(actionList);
            }
        }
        this.setActionState('waiting');
    };


    _enemyId: number;
    _letter: string;
    _plural: boolean;
    _screenX: number;
    _screenY: number;
}
// Game_Actors
//
// The wrapper class for an actor array.

 class Game_Actors {

    _data: Game_Actor[];

    constructor() {
        this.initialize.apply(this, arguments);
    };
    initialize(): void {
        this._data = [];
    };
    

    actor(actorId: number): Game_Actor {
        if ($dataActors[actorId]) {
            if (!this._data[actorId]) {
                this._data[actorId] = new Game_Actor(actorId);
            }
            return this._data[actorId];
        }
        return null;
    };
}


//-----------------------------------------------------------------------------
// Game_Unit
//
// The superclass of Game_Party and Game_Troop.

class Game_Unit {
    _inBattle: boolean;
    constructor(...args: any[]) {
        this.initialize(...args);
        //this.initialize.apply(this, arguments);
    };
    initialize(...args: any[]): void {
        this._inBattle = false;
    };
    

    inBattle(): boolean {
        return this._inBattle;
    };
    members(): Game_Battler[]|any {
        return [];
    };
    aliveMembers(): Game_Battler[] {
        return this.members().filter(function(member:any) {
            return member.isAlive();
        });
    };
    deadMembers(): Game_Battler[] {
        return this.members().filter(function(member:any) {
            return member.isDead();
        });
    };
    movableMembers(): Game_Battler[] {
        return this.members().filter(function(member:any) {
            return member.canMove();
        });
    };
    clearActions(): void {
        return this.members().forEach(function(member:any) {
            return member.clearActions();
        });
    };
    agility(): number {
        var members = this.members();
        if (members.length === 0) {
            return 1;
        }
        var sum = members.reduce(function(r:any, member:any) {
            return r + member.agi;
        }, 0);
        return sum / members.length;
    };
    tgrSum(): number {
        return this.aliveMembers().reduce(function(r, member) {
            return r + member.tgr;
        }, 0);
    };
    randomTarget(): Game_Battler {
        var tgrRand = Math.random() * this.tgrSum();
        var target:any = null;
        this.aliveMembers().forEach(function(member) {
            tgrRand -= member.tgr;
            if (tgrRand <= 0 && !target) {
                target = member;
            }
        });
        return target;
    };
    randomDeadTarget(): Game_Battler {
        var members = this.deadMembers();
        if (members.length === 0) {
            return null;
        }
        return members[Math.floor(Math.random() * members.length)];
    };
    smoothTarget(index?:number): Game_Battler{
        if (index < 0) {
            index = 0;
        }
        var member = this.members()[index];
        return (member && member.isAlive()) ? member : this.aliveMembers()[0];
    };
    smoothDeadTarget(index?:number): Game_Battler {
        if (index < 0) {
            index = 0;
        }
        var member = this.members()[index];
        return (member && member.isDead()) ? member : this.deadMembers()[0];
    };
    clearResults(): void {
        this.members().forEach(function(member:any) {
            member.clearResult();
        });
    };
    onBattleStart(): void {
        this.members().forEach(function(member:any) {
            member.onBattleStart();
        });
        this._inBattle = true;
    };
    onBattleEnd(): void {
        this._inBattle = false;
        this.members().forEach(function(member:any) {
            member.onBattleEnd();
        });
    };
    makeActions(): void {
        this.members().forEach(function(member:any) {
            member.makeActions();
        });
    };
    select(activeMember:any): void {
        this.members().forEach(function(member:any) {
            if (member === activeMember) {
                member.select();
            } else {
                member.deselect();
            }
        });
    };
    isAllDead(): boolean {
        return this.aliveMembers().length === 0;
    };
    substituteBattler(): Game_Battler {
        var members = this.members();
        for (var i = 0; i < members.length; i++) {
            if (members[i].isSubstitute()) {
                return members[i];
            }
        }
    };
}

//-----------------------------------------------------------------------------
// Game_Party
//
// The game object class for the party. Information such as gold and items is
// included.

class Game_Party extends Game_Unit {

    _gold: number;
    _steps: number;
    _lastItem: Game_Item;
    _menuActorId: number;
    _targetActorId: number;
    _actors: number[];
    _items: { [key: number]: number };
    _weapons: { [key: number]: number };
    _armors: { [key: number]: number };


    //constructor() {
    //    this.initialize.apply(this, arguments);
    //};

    constructor(...args: any[]) {
        super();
        this.initialize(...args);
    }

    static ABILITY_ENCOUNTER_HALF: 0 =0;
    static ABILITY_ENCOUNTER_NONE: 1 = 1;
    static ABILITY_CANCEL_SURPRISE: 2=2;
    static ABILITY_RAISE_PREEMPTIVE: 3=3;
    static ABILITY_GOLD_DOUBLE: 4=4;
    static ABILITY_DROP_ITEM_DOUBLE: 5=5;

    initialize(...args: any[]): void {
        Game_Unit.prototype.initialize.call(this);
        this._gold = 0;
        this._steps = 0;
        this._lastItem = new Game_Item();
        this._menuActorId = 0;
        this._targetActorId = 0;
        this._actors = [];
        this.initAllItems();
    };

    initAllItems(): void {
        this._items = {};
        this._weapons = {};
        this._armors = {};
    };

    exists(): boolean{
        return this._actors.length > 0;
    };
    size(): number {
        return this.members().length;
    };
    isEmpty(): boolean {
        return this.size() === 0;
    };
    members(): Game_Actor[] {
        return this.inBattle() ? this.battleMembers() : this.allMembers();
    };
    allMembers(): Game_Actor[] {
        return this._actors.map(function(id) {
            return $gameActors.actor(id);
        });
    };
    battleMembers(): Game_Actor[] {
        return this.allMembers().slice(0, this.maxBattleMembers()).filter(function(actor) {
            return actor.isAppeared();
        });
    };
    maxBattleMembers(): number {
        return 4;
    };
    leader(): Game_Actor {
        return this.battleMembers()[0];
    };
    reviveBattleMembers(): any {
        this.battleMembers().forEach(function(actor) {
            if (actor.isDead()) {
                actor.setHp(1);
            }
        });
    };
    items(): RPGMakerMV.DataItem[] {
        var list = [];
        for (var id in this._items) {
            list.push($dataItems[id]);
        }
        return list;
    };
    weapons(): RPGMakerMV.DataWeapon[] {
        var list = [];
        for (var id in this._weapons) {
            list.push($dataWeapons[id]);
        }
        return list;
    };
    armors(): any {
        var list = [];
        for (var id in this._armors) {
            list.push($dataArmors[id]);
        }
        return list;
    };
    equipItems(): any {
        return this.weapons().concat(this.armors());
    };
    allItems(): RPGMakerMV.DataAnyItem[] {
        return this.items().concat(this.equipItems());
    };
    itemContainer(item: RPGMakerMV.DataAnyItem): any {
        if (!item) {
            return null;
        } else if (DataManager.isItem(item)) {
            return this._items;
        } else if (DataManager.isWeapon(item)) {
            return this._weapons;
        } else if (DataManager.isArmor(item)) {
            return this._armors;
        } else {
            return null;
        }
    };
    setupStartingMembers(): void {
        this._actors = [];
        $dataSystem.partyMembers.forEach(function(this:any,actorId:any) {
            if ($gameActors.actor(actorId)) {
                this._actors.push(actorId);
            }
        }, this);
    };
    name(): string {
        var numBattleMembers = this.battleMembers().length;
        if (numBattleMembers === 0) {
            return '';
        } else if (numBattleMembers === 1) {
            return this.leader().name();
        } else {
            return TextManager.partyName.format(this.leader().name());
        }
    };
    setupBattleTest(): void {
        this.setupBattleTestMembers();
        this.setupBattleTestItems();
    };
    setupBattleTestMembers(): void {
        $dataSystem.testBattlers.forEach(function(this:any,battler:any) {
            var actor = $gameActors.actor(battler.actorId);
            if (actor) {
                actor.changeLevel(battler.level, false);
                actor.initEquips(battler.equips);
                actor.recoverAll();
                this.addActor(battler.actorId);
            }
        }, this);
    };
    setupBattleTestItems(): void {
        $dataItems.forEach(function(this:any,item:any) {
            if (item && item.name.length > 0) {
                this.gainItem(item, this.maxItems(item));
            }
        }, this);
    };
    highestLevel(): number {
        return Math.max.apply(null, this.members().map(function(actor) {
            return actor.level;
        }));
    };
    addActor(actorId: number): void {
        if (!this._actors.contains(actorId)) {
            this._actors.push(actorId);
            $gamePlayer.refresh();
            $gameMap.requestRefresh();
        }
    };
    removeActor(actorId: number): void {
        if (this._actors.contains(actorId)) {
            this._actors.splice(this._actors.indexOf(actorId), 1);
            $gamePlayer.refresh();
            $gameMap.requestRefresh();
        }
    };
    gold(): number {
        return this._gold;
    };
    gainGold(amount: number): void {
        this._gold = (this._gold + amount).clamp(0, this.maxGold());
    };
    loseGold(amount: number): void {
        this.gainGold(-amount);
    };
    maxGold(): number{
        return 99999999;
    };
    steps(): number {
        return this._steps;
    };
    increaseSteps(): void {
        this._steps++;
    };
    numItems(item: RPGMakerMV.DataAnyItem): number |any{
        var container = this.itemContainer(item);
        return container ? container[item.id] || 0 : 0;
    };
    maxItems(item: RPGMakerMV.DataAnyItem): number {
        return 99;
    };
    hasMaxItems(item: RPGMakerMV.DataAnyItem): boolean {
        return this.numItems(item) >= this.maxItems(item);
    };
    hasItem(item: RPGMakerMV.DataAnyItem, includeEquip?: boolean): boolean {
        if (includeEquip === undefined) {
            includeEquip = false;
        }
        if (this.numItems(item) > 0) {
            return true;
        } else if (includeEquip && this.isAnyMemberEquipped(item)) {
            return true;
        } else {
            return false;
        }
    };
    isAnyMemberEquipped(item: RPGMakerMV.DataAnyItem): boolean {
        return this.members().some(function(actor) {
            return actor.equips().contains(item);
        });
    };
    gainItem(item: RPGMakerMV.DataAnyItem, amount: number, includeEquip?: boolean): void {
        var container = this.itemContainer(item);
        if (container) {
            var lastNumber = this.numItems(item);
            var newNumber = lastNumber + amount;
            container[item.id] = newNumber.clamp(0, this.maxItems(item));
            if (container[item.id] === 0) {
                delete container[item.id];
            }
            if (includeEquip && newNumber < 0) {
                this.discardMembersEquip(item, -newNumber);
            }
            $gameMap.requestRefresh();
        }
    };
    discardMembersEquip(item: RPGMakerMV.DataAnyItem, amount: number): void {
        var n = amount;
        this.members().forEach(function(actor) {
            while (n > 0 && actor.isEquipped(item)) {
                actor.discardEquip(item);
                n--;
            }
        });
    };
    loseItem(item: RPGMakerMV.DataAnyItem, amount: number, includeEquip?: boolean): void {
        this.gainItem(item, -amount, includeEquip);
    };
    consumeItem(item: RPGMakerMV.DataAnyItem): void {
        if (DataManager.isItem(item) && item.consumable) {
            this.loseItem(item, 1);
        }
    };
    canUse(item: RPGMakerMV.DataAnyItem): boolean {
        return this.members().some(function(actor) {
            return actor.canUse(item);
        });
    };
    canInput(): boolean {
        return this.members().some(function(actor) {
            return actor.canInput();
        });
    };
    isAllDead(): boolean {
        if (Game_Unit.prototype.isAllDead.call(this)) {
            return this.inBattle() || !this.isEmpty();
        } else {
            return false;
        }
    };
    onPlayerWalk(): void {
        this.members().forEach(function(actor) {
            return actor.onPlayerWalk();
        });
    };
    menuActor(): Game_Actor {
        var actor = $gameActors.actor(this._menuActorId);
        if (!this.members().contains(actor)) {
            actor = this.members()[0];
        }
        return actor;
    };
    setMenuActor(actor: Game_Actor): void {
        this._menuActorId = actor.actorId();
    };
    makeMenuActorNext(): void {
        var index = this.members().indexOf(this.menuActor());
        if (index >= 0) {
            index = (index + 1) % this.members().length;
            this.setMenuActor(this.members()[index]);
        } else {
            this.setMenuActor(this.members()[0]);
        }
    };
    makeMenuActorPrevious(): void {
        var index = this.members().indexOf(this.menuActor());
        if (index >= 0) {
            index = (index + this.members().length - 1) % this.members().length;
            this.setMenuActor(this.members()[index]);
        } else {
            this.setMenuActor(this.members()[0]);
        }
    };
    targetActor(): Game_Actor {
        var actor = $gameActors.actor(this._targetActorId);
        if (!this.members().contains(actor)) {
            actor = this.members()[0];
        }
        return actor;
    };
    setTargetActor(actor: Game_Actor): void {
        this._targetActorId = actor.actorId();
    };
    lastItem(): any {
        return this._lastItem.object();
    };
    setLastItem(item: RPGMakerMV.DataAnyItem|any): void {
        this._lastItem.setObject(item);
    };
    swapOrder(index1: number, index2: number): void{
        var temp = this._actors[index1];
        this._actors[index1] = this._actors[index2];
        this._actors[index2] = temp;
        $gamePlayer.refresh();
    };
    charactersForSavefile(): any{
        return this.battleMembers().map(function(actor) {
            return [actor.characterName(), actor.characterIndex()];
        });
    };
    facesForSavefile(): any{
        return this.battleMembers().map(function(actor) {
            return [actor.faceName(), actor.faceIndex()];
        });
    };
    partyAbility(abilityId: number): boolean{
        return this.battleMembers().some(function(actor) {
            return actor.partyAbility(abilityId);
        });
    };
    hasEncounterHalf(): boolean{
        return this.partyAbility(Game_Party.ABILITY_ENCOUNTER_HALF);
    };
    hasEncounterNone(): boolean {
        return this.partyAbility(Game_Party.ABILITY_ENCOUNTER_NONE);
    };
    hasCancelSurprise(): boolean {
        return this.partyAbility(Game_Party.ABILITY_CANCEL_SURPRISE);
    };
    hasRaisePreemptive(): boolean {
        return this.partyAbility(Game_Party.ABILITY_RAISE_PREEMPTIVE);
    };
    hasGoldDouble(): boolean {
        return this.partyAbility(Game_Party.ABILITY_GOLD_DOUBLE);
    };
    hasDropItemDouble(): boolean {
        return this.partyAbility(Game_Party.ABILITY_DROP_ITEM_DOUBLE);
    };
    ratePreemptive(troopAgi: number): number {
        var rate = this.agility() >= troopAgi ? 0.05 : 0.03;
        if (this.hasRaisePreemptive()) {
            rate *= 4;
        }
        return rate;
    };
    rateSurprise(troopAgi: number): number {
        var rate = this.agility() >= troopAgi ? 0.03 : 0.05;
        if (this.hasCancelSurprise()) {
            rate = 0;
        }
        return rate;
    };
    performVictory(): void {
        this.members().forEach(function(actor) {
            actor.performVictory();
        });
    };
    performEscape(): void {
        this.members().forEach(function(actor) {
            actor.performEscape();
        });
    };
    removeBattleStates(): void {
        this.members().forEach(function(actor) {
            actor.removeBattleStates();
        });
    };
    requestMotionRefresh(): void {
        this.members().forEach(function(actor) {
            actor.requestMotionRefresh();
        });
    };
}

//-----------------------------------------------------------------------------
// Game_Troop
//
// The game object class for a troop and the battle-related data.

class Game_Troop extends Game_Unit {

    constructor(...args: any[]) {
        super(...args);
        this.initialize(...args);

    }

    static LETTER_TABLE_HALF: RPGMakerMV.DefaultLetterTableHalf = [
        ' A',' B',' C',' D',' E',' F',' G',' H',' I',' J',' K',' L',' M',
        ' N',' O',' P',' Q',' R',' S',' T',' U',' V',' W',' X',' Y',' Z'
    ];

    static LETTER_TABLE_FULL: RPGMakerMV.DefaultLetterTableFull = [
        'Ａ','Ｂ','Ｃ','Ｄ','Ｅ','Ｆ','Ｇ','Ｈ','Ｉ','Ｊ','Ｋ','Ｌ','Ｍ',
        'Ｎ','Ｏ','Ｐ','Ｑ','Ｒ','Ｓ','Ｔ','Ｕ','Ｖ','Ｗ','Ｘ','Ｙ','Ｚ'
    ];

    initialize(...args: any[]): void {
        Game_Unit.prototype.initialize.call(this);
        this._interpreter = new Game_Interpreter();
        this.clear();
    };
    
    isEventRunning(): boolean {
        return this._interpreter.isRunning();
    };
    updateInterpreter(): void {
        this._interpreter.update();
    };
    turnCount(): number {
        return this._turnCount;
    };
    members(): Game_Enemy[] {
        return this._enemies;
    };
    clear(): void{
        this._interpreter.clear();
        this._troopId = 0;
        this._eventFlags = {};
        this._enemies = [];
        this._turnCount = 0;
        this._namesCount = {};
    };
    troop(): RPGMakerMV.DataTroop {
        return $dataTroops[this._troopId];
    };
    setup(troopId: number): void {
        this.clear();
        this._troopId = troopId;
        this._enemies = [];
        this.troop().members.forEach(function(this:any,member:any) {
            if ($dataEnemies[member.enemyId]) {
                var enemyId:any = member.enemyId;
                var x:any = member.x;
                var y:any = member.y;
                var enemy = new Game_Enemy(enemyId, x, y);
                if (member.hidden) {
                    enemy.hide();
                }
                this._enemies.push(enemy);
            }
        }, this);
        this.makeUniqueNames();
    };
    makeUniqueNames(): void {
        var table = this.letterTable();
        this.members().forEach(function(this:any,enemy:any) {
            if (enemy.isAlive() && enemy.isLetterEmpty()) {
                var name = enemy.originalName();
                var n = this._namesCount[name] || 0;
                enemy.setLetter(table[n % table.length]);
                this._namesCount[name] = n + 1;
            }
        }, this);
        this.members().forEach(function(this:any,enemy:any) {
            var name = enemy.originalName();
            if (this._namesCount[name] >= 2) {
                enemy.setPlural(true);
            }
        }, this);
    };
    letterTable(): string[] {
        return $gameSystem.isCJK() ? Game_Troop.LETTER_TABLE_FULL :
                Game_Troop.LETTER_TABLE_HALF;
    };
    enemyNames(): string[] {
        var names:any = [];
        this.members().forEach(function(enemy) {
            var name = enemy.originalName();
            if (enemy.isAlive() && !names.contains(name)) {
                names.push(name);
            }
        });
        return names;
    };
    meetsConditions(page: RPGMakerMV.BattleEventPage): boolean {
        var c:any = page.conditions;
        if (!c.turnEnding && !c.turnValid && !c.enemyValid &&
                !c.actorValid && !c.switchValid) {
            return false;  // Conditions not set
        }
        if (c.turnEnding) {
            if (!BattleManager.isTurnEnd()) {
                return false;
            }
        }
        if (c.turnValid) {
            var n = this._turnCount;
            var a = c.turnA;
            var b = c.turnB;
            if ((b === 0 && n !== a)) {
                return false;
            }
            if ((b > 0 && (n < 1 || n < a || n % b !== a % b))) {
                return false;
            }
        }
        if (c.enemyValid) {
            var enemy = $gameTroop.members()[c.enemyIndex];
            if (!enemy || enemy.hpRate() * 100 > c.enemyHp) {
                return false;
            }
        }
        if (c.actorValid) {
            var actor = $gameActors.actor(c.actorId);
            if (!actor || actor.hpRate() * 100 > c.actorHp) {
                return false;
            }
        }
        if (c.switchValid) {
            if (!$gameSwitches.value(c.switchId)) {
                return false;
            }
        }
        return true;
    };
    setupBattleEvent(): void {
        if (!this._interpreter.isRunning()) {
            if (this._interpreter.setupReservedCommonEvent()) {
                return;
            }
            var pages = this.troop().pages;
            for (var i = 0; i < pages.length; i++) {
                var page = pages[i];
                if (this.meetsConditions(page) && !this._eventFlags[i]) {
                    this._interpreter.setup(page.list);
                    if (page.span <= 1) {
                        this._eventFlags[i] = true;
                    }
                    break;
                }
            }
        }
    };
    increaseTurn(): void {
        var pages = this.troop().pages;
        for (var i = 0; i < pages.length; i++) {
            var page = pages[i];
            if (page.span === 1) {
                this._eventFlags[i] = false;
            }
        }
        this._turnCount++;
    };
    expTotal(): number {
        return this.deadMembers().reduce(function(r:any, enemy:any) {
            return r + enemy.exp();
        }, 0);
    };
    goldTotal(): number {
        return this.deadMembers().reduce(function(r:any, enemy:any) {
            return r + enemy.gold();
        }, 0) * this.goldRate();
    };
    goldRate(): number {
        return $gameParty.hasGoldDouble() ? 2 : 1;
    };
    makeDropItems(): RPGMakerMV.DataAnyItem[] {
        return this.deadMembers().reduce(function(r:any, enemy:any) {
            return r.concat(enemy.makeDropItems());
        }, []);
    };

    _interpreter: Game_Interpreter;
    _turnCount: number;
    _enemies: Game_Enemy[];
    _troopId: number;
    _eventFlags: { [key: number]: boolean };
    _namesCount: { [key: string]: number };
}

//===========  待处理  ============
//-----------------------------------------------------------------------------
// Game_Map
//
// The game object class for a map. It contains scrolling and passage
// determination functions.
class Game_Map {
    constructor(...args: any[]) {
        this.initialize(...args);

    }

    initialize(...args: any[]): void {
        this._interpreter = new Game_Interpreter();
        this._mapId = 0;
        this._tilesetId = 0;
        this._events = [];
        this._commonEvents = [];
        this._vehicles = [];
        this._displayX = 0;
        this._displayY = 0;
        this._nameDisplay = true;
        this._scrollDirection = 2;
        this._scrollRest = 0;
        this._scrollSpeed = 4;
        this._parallaxName = '';
        this._parallaxZero = false;
        this._parallaxLoopX = false;
        this._parallaxLoopY = false;
        this._parallaxSx = 0;
        this._parallaxSy = 0;
        this._parallaxX = 0;
        this._parallaxY = 0;
        this._battleback1Name = null;
        this._battleback2Name = null;
        this.createVehicles();
    };

    _interpreter: Game_Interpreter;
    _mapId: number;
    _tilesetId: number;
    _events: Game_Event[];
    _commonEvents: Game_CommonEvent[];
    _vehicles: Game_Vehicle[];
    _displayX: number;
    _displayY: number;
    _nameDisplay: boolean;
    _scrollDirection: number;
    _scrollRest: number;
    _scrollSpeed: number;
    _parallaxName: string;
    _parallaxZero: boolean;
    _parallaxLoopX: boolean;
    _parallaxLoopY: boolean;
    _parallaxSx: number;
    _parallaxSy: number;
    _parallaxX: number;
    _parallaxY: number;
    _battleback1Name: string;
    _battleback2Name: string;

    setup(mapId: number): void {
        if (!$dataMap) {
            throw new Error('The map data is not available');
        }
        this._mapId = mapId;
        this._tilesetId = $dataMap.tilesetId;
        this._displayX = 0;
        this._displayY = 0;
        this.refereshVehicles();
        this.setupEvents();
        this.setupScroll();
        this.setupParallax();
        this.setupBattleback();
        this._needsRefresh = false;
    };
    
    _needsRefresh: boolean;

    isEventRunning(): boolean {
        return this._interpreter.isRunning() || this.isAnyEventStarting();
    };

    tileWidth(): number {
        return 48;
    };

    tileHeight(): number {
        return 48;
    };

    mapId(): number {
        return this._mapId;
    };

    tilesetId(): number {
        return this._tilesetId;
    };

    displayX(): number{
        return this._displayX;
    };

    displayY(): number {
        return this._displayY;
    };

    parallaxName(): string {
        return this._parallaxName;
    };

    battleback1Name(): string {
        return this._battleback1Name;
    };

    battleback2Name(): string {
        return this._battleback2Name;
    };

    requestRefresh(mapId: number): void {
        this._needsRefresh = true;
    };

    isNameDisplayEnabled(): boolean {
        return this._nameDisplay;
    };

    disableNameDisplay(): void {
        this._nameDisplay = false;
    };

    enableNameDisplay(): void {
        this._nameDisplay = true;
    };

    createVehicles(): void {
        this._vehicles = [];
        this._vehicles[0] = new Game_Vehicle('boat');
        this._vehicles[1] = new Game_Vehicle('ship');
        this._vehicles[2] = new Game_Vehicle('airship');
    };

    refereshVehicles(): void {
        this._vehicles.forEach(function(vehicle) {
            vehicle.refresh();
        });
    };

    vehicles(): Game_Vehicle[] {
        return this._vehicles;
    };

    vehicle(type: string|number): Game_Vehicle {
        if (type ===  0 || type === 'boat') {
            return this.boat();
        } else if (type ===  1 || type === 'ship') {
            return this.ship();
        } else if (type ===  2 || type === 'airship') {
            return this.airship();
        } else {
            return null;
        }
    };

    boat(): Game_Vehicle {
        return this._vehicles[0];
    };

    ship(): Game_Vehicle {
        return this._vehicles[1];
    };

    airship(): Game_Vehicle {
        return this._vehicles[2];
    };

    setupEvents(): void {
        this._events = [];
        for (var i = 0; i < $dataMap.events.length; i++) {
            if ($dataMap.events[i]) {
                this._events[i] = new Game_Event(this._mapId, i);
            }
        }
        this._commonEvents = this.parallelCommonEvents().map(function(commonEvent) {
            return new Game_CommonEvent(commonEvent.id);
        });
        this.refreshTileEvents();
    };

    events(): Game_Event[] {
        return this._events.filter(function(event) {
            return !!event;
        });
    };

    event(eventId: number): Game_Event {
        return this._events[eventId];
    };

    eraseEvent(eventId: number): void {
        this._events[eventId].erase();
    };

    parallelCommonEvents(): RPGMakerMV.DataCommonEvent[] {
        return $dataCommonEvents.filter(commonEvent => {
             commonEvent && commonEvent.trigger === 2;
        });
    };
    
    setupScroll(): void {
        this._scrollDirection = 2;
        this._scrollRest = 0;
        this._scrollSpeed = 4;
    };

    setupParallax(): void {
        this._parallaxName = $dataMap.parallaxName || '';
        this._parallaxZero = ImageManager.isZeroParallax(this._parallaxName);
        this._parallaxLoopX = $dataMap.parallaxLoopX;
        this._parallaxLoopY = $dataMap.parallaxLoopY;
        this._parallaxSx = $dataMap.parallaxSx;
        this._parallaxSy = $dataMap.parallaxSy;
        this._parallaxX = 0;
        this._parallaxY = 0;
    };

    setupBattleback(): void {
        if ($dataMap.specifyBattleback) {
            this._battleback1Name = $dataMap.battleback1Name;
            this._battleback2Name = $dataMap.battleback2Name;
        } else {
            this._battleback1Name = null;
            this._battleback2Name = null;
        }
    };

    setDisplayPos(x: number, y: number): void {
        if (this.isLoopHorizontal()) {
            this._displayX = x.mod(this.width());
            this._parallaxX = x;
        } else {
            var endX = this.width() - this.screenTileX();
            this._displayX = endX < 0 ? endX / 2 : x.clamp(0, endX);
            this._parallaxX = this._displayX;
        }
        if (this.isLoopVertical()) {
            this._displayY = y.mod(this.height());
            this._parallaxY = y;
        } else {
            var endY = this.height() - this.screenTileY();
            this._displayY = endY < 0 ? endY / 2 : y.clamp(0, endY);
            this._parallaxY = this._displayY;
        }
    };

    parallaxOx(): number {
        if (this._parallaxZero) {
            return this._parallaxX * this.tileWidth();
        } else if (this._parallaxLoopX) {
            return this._parallaxX * this.tileWidth() / 2;
        } else {
            return 0;
        }
    };

    parallaxOy(): number {
        if (this._parallaxZero) {
            return this._parallaxY * this.tileHeight();
        } else if (this._parallaxLoopY) {
            return this._parallaxY * this.tileHeight() / 2;
        } else {
            return 0;
        }
    };

    tileset(): RPGMakerMV.DataTileset {
        return $dataTilesets[this._tilesetId];
    };

    tilesetFlags(): number[] {
        let tileset = this.tileset();
        if (tileset) {
            return tileset.flags;
        } else {
            return [];
        }
    };

    displayName(): string {
        return $dataMap.displayName;
    };

    width(): number {
        return $dataMap.width;
    };

    height(): number {
        return $dataMap.height;
    };

    data(): number[] {
        return $dataMap.data;
    };

    isLoopHorizontal(): boolean {
        return $dataMap.scrollType === 2 || $dataMap.scrollType === 3;
    };

    isLoopVertical(): boolean {
        return $dataMap.scrollType === 1 || $dataMap.scrollType === 3;
    };

    isDashDisabled(): boolean {
        return $dataMap.disableDashing;
    };

    encounterList(): RPGMakerMV.Encounter[] {
        return $dataMap.encounterList;
    };

    encounterStep(): number {
        return $dataMap.encounterStep;
    };

    isOverworld(): boolean {
        return this.tileset() && this.tileset().mode === 0;
    };

    screenTileX(): number {
        return Graphics.width / this.tileWidth();
    };

    screenTileY(): number {
        return Graphics.height / this.tileHeight();
    };

    adjustX(x: number): number {
        if (this.isLoopHorizontal() && x < this._displayX -
                (this.width() - this.screenTileX()) / 2) {
            return x - this._displayX + $dataMap.width;
        } else {
            return x - this._displayX;
        }
    };

    adjustY(y: number): number {
        if (this.isLoopVertical() && y < this._displayY -
                (this.height() - this.screenTileY()) / 2) {
            return y - this._displayY + $dataMap.height;
        } else {
            return y - this._displayY;
        }
    };

    roundX(x: number): number {
        return this.isLoopHorizontal() ? x.mod(this.width()) : x;
    };

    roundY(y: number): number {
        return this.isLoopVertical() ? y.mod(this.height()) : y;
    };

    xWithDirection(x: number, d: number): number {
        return x + (d === 6 ? 1 : d === 4 ? -1 : 0);
    };

    yWithDirection(y: number, d: number): number {
        return y + (d === 2 ? 1 : d === 8 ? -1 : 0);
    };

    roundXWithDirection(x: number, d: number): number {
        return this.roundX(x + (d === 6 ? 1 : d === 4 ? -1 : 0));
    };

    roundYWithDirection(y: number, d: number): number {
        return this.roundY(y + (d === 2 ? 1 : d === 8 ? -1 : 0));
    };

    deltaX(x1: number, x2: number): number {
        let result = x1 - x2;
        if (this.isLoopHorizontal() && Math.abs(result) > this.width() / 2) {
            if (result < 0) {
                result += this.width();
            } else {
                result -= this.width();
            }
        }
        return result;
    };

    deltaY(y1: number, y2: number): number {
        let result = y1 - y2;
        if (this.isLoopVertical() && Math.abs(result) > this.height() / 2) {
            if (result < 0) {
                result += this.height();
            } else {
                result -= this.height();
            }
        }
        return result;
    };

    distance(x1: number, y1: number, x2: number, y2: number): number {
        return Math.abs(this.deltaX(x1, x2)) + Math.abs(this.deltaY(y1, y2));
    };

    canvasToMapX(x: number): number {
        let tileWidth = this.tileWidth();
        let originX = this._displayX * tileWidth;
        let mapX = Math.floor((originX + x) / tileWidth);
        return this.roundX(mapX);
    };

    canvasToMapY(y: number): number {
        let tileHeight = this.tileHeight();
        let originY = this._displayY * tileHeight;
        let mapY = Math.floor((originY + y) / tileHeight);
        return this.roundY(mapY);
    };

    autoplay(): void {
        if ($dataMap.autoplayBgm) {
            if ($gamePlayer.isInVehicle()) {
                $gameSystem.saveWalkingBgm2();
            } else {
                AudioManager.playBgm($dataMap.bgm);
            }
        }
        if ($dataMap.autoplayBgs) {
            AudioManager.playBgs($dataMap.bgs);
        }
    };

    refreshIfNeeded(): void {
        if (this._needsRefresh) {
            this.refresh();
        }
    };
    
    refresh(): void {
        this.events().forEach(function(event) {
            event.refresh();
        });
        this._commonEvents.forEach(function(event) {
            event.refresh();
        });
        this.refreshTileEvents();
        this._needsRefresh = false;
    };

    tileEvents: Game_Event[];

    refreshTileEvents(): void {
        this.tileEvents = this.events().filter(event => {
            return event.isTile();
        });
    };

    eventsXy(x: number, y: number): Game_Event[] {
        return this.events().filter(function(event) {
            return event.pos(x, y);
        });
    };

    eventsXyNt(x: number, y: number): Game_Event[] {
        return this.events().filter(function(event) {
            return event.posNt(x, y);
        });
    };

    tileEventsXy(x: number, y: number): Game_Event[] {
        return this.tileEvents.filter(function(event) {
            return event.posNt(x, y);
        });
    };

    eventIdXy(x: number, y: number): number {
        var list = this.eventsXy(x, y);
        return list.length === 0 ? 0 : list[0].eventId();
    };

    scrollDown(distance: number): void {
        if (this.isLoopVertical()) {
            this._displayY += distance;
            this._displayY %= $dataMap.height;
            if (this._parallaxLoopY) {
                this._parallaxY += distance;
            }
        } else if (this.height() >= this.screenTileY()) {
            var lastY = this._displayY;
            this._displayY = Math.min(this._displayY + distance,
                this.height() - this.screenTileY());
            this._parallaxY += this._displayY - lastY;
        }
    };

    scrollLeft(distance: number): void {
        if (this.isLoopHorizontal()) {
            this._displayX += $dataMap.width - distance;
            this._displayX %= $dataMap.width;
            if (this._parallaxLoopX) {
                this._parallaxX -= distance;
            }
        } else if (this.width() >= this.screenTileX()) {
            let lastX = this._displayX;
            this._displayX = Math.max(this._displayX - distance, 0);
            this._parallaxX += this._displayX - lastX;
        }
    };

    scrollRight(distance: number): void {
        if (this.isLoopHorizontal()) {
            this._displayX += distance;
            this._displayX %= $dataMap.width;
            if (this._parallaxLoopX) {
                this._parallaxX += distance;
            }
        } else if (this.width() >= this.screenTileX()) {
            let lastX = this._displayX;
            this._displayX = Math.min(this._displayX + distance,
                this.width() - this.screenTileX());
            this._parallaxX += this._displayX - lastX;
        }
    };

    scrollUp(distance: number): void {
        if (this.isLoopVertical()) {
            this._displayY += $dataMap.height - distance;
            this._displayY %= $dataMap.height;
            if (this._parallaxLoopY) {
                this._parallaxY -= distance;
            }
        } else if (this.height() >= this.screenTileY()) {
            let lastY = this._displayY;
            this._displayY = Math.max(this._displayY - distance, 0);
            this._parallaxY += this._displayY - lastY;
        }
    };

    isValid(x: number, y: number): boolean {
        return x >= 0 && x < this.width() && y >= 0 && y < this.height();
    };

    checkPassage(x: number, y: number, bit: number): boolean {
        let flags = this.tilesetFlags();
        let tiles = this.allTiles(x, y);
        for (let i = 0; i < tiles.length; i++) {
            let flag = flags[tiles[i]];
            if ((flag & 0x10) !== 0)  // [*] No effect on passage
                continue;
            if ((flag & bit) === 0)   // [o] Passable
                return true;
            if ((flag & bit) === bit) // [x] Impassable
                return false;
        }
        return false;
    };

    tileId(x: number, y: number, z: number): number{
        let width = $dataMap.width;
        let height = $dataMap.height;
        return $dataMap.data[(z * height + y) * width + x] || 0;
    };

    layeredTiles(x: number, y: number): number[] {
        let tiles = [];
        for (let i = 0; i < 4; i++) {
            tiles.push(this.tileId(x, y, 3 - i));
        }
        return tiles;
    };

    allTiles(x: number, y: number): number[] {
        let tiles:any = this.tileEventsXy(x, y).map(event => {
            return event.tileId();
        });
        return tiles.concat(this.layeredTiles(x, y));
    };

    autotileType(x: number, y: number, z: number): number {
        var tileId = this.tileId(x, y, z);
        return tileId >= 2048 ? Math.floor((tileId - 2048) / 48) : -1;
    };

    isPassable(x: number, y: number, d: number): boolean {
        return this.checkPassage(x, y, (1 << (d / 2 - 1)) & 0x0f);
    };

    isBoatPassable(x: number, y: number): boolean {
        return this.checkPassage(x, y, 0x0200);
    };

    isShipPassable(x: number, y: number): boolean {
        return this.checkPassage(x, y, 0x0400);
    };

    isAirshipLandOk(x: number, y: number): boolean {
        return this.checkPassage(x, y, 0x0800) && this.checkPassage(x, y, 0x0f);
    };

    checkLayeredTilesFlags(x: number, y: number, bit: number): boolean {
        var flags = this.tilesetFlags();
        return this.layeredTiles(x, y).some(function(tileId) {
            return (flags[tileId] & bit) !== 0;
        });
    };

    isLadder(x: number, y: number): boolean {
        return this.isValid(x, y) && this.checkLayeredTilesFlags(x, y, 0x20);
    };

    isBush(x: number, y: number): boolean {
        return this.isValid(x, y) && this.checkLayeredTilesFlags(x, y, 0x40);
    };

    isCounter(x: number, y: number): boolean {
        return this.isValid(x, y) && this.checkLayeredTilesFlags(x, y, 0x80);
    };

    isDamageFloor(x: number, y: number): boolean {
        return this.isValid(x, y) && this.checkLayeredTilesFlags(x, y, 0x100);
    };

    terrainTag(x: number, y: number): number {
        if (this.isValid(x, y)) {
            let flags = this.tilesetFlags();
            let tiles = this.layeredTiles(x, y);
            for (let i = 0; i < tiles.length; i++) {
                let tag = flags[tiles[i]] >> 12;
                if (tag > 0) {
                    return tag;
                }
            }
        }
        return 0;
    };

    regionId(x: number, y: number): number {
        return this.isValid(x, y) ? this.tileId(x, y, 5) : 0;
    };

    startScroll(direction: number, distance: number, speed: number): void {
        this._scrollDirection = direction;
        this._scrollRest = distance;
        this._scrollSpeed = speed;
    };

    isScrolling(): boolean {
        return this._scrollRest > 0;
    };

    update(sceneActive: boolean): void {
        this.refreshIfNeeded();
        if (sceneActive) {
            this.updateInterpreter();
        }
        this.updateScroll();
        this.updateEvents();
        this.updateVehicles();
        this.updateParallax();
    };

    updateScroll(): void {
        if (this.isScrolling()) {
            var lastX = this._displayX;
            var lastY = this._displayY;
            this.doScroll(this._scrollDirection, this.scrollDistance());
            if (this._displayX === lastX && this._displayY === lastY) {
                this._scrollRest = 0;
            } else {
                this._scrollRest -= this.scrollDistance();
            }
        }
    };

    scrollDistance(): number {
        return Math.pow(2, this._scrollSpeed) / 256;
    };

    doScroll(direction: number, distance: number): void {
        switch (direction) {
        case 2:
            this.scrollDown(distance);
            break;
        case 4:
            this.scrollLeft(distance);
            break;
        case 6:
            this.scrollRight(distance);
            break;
        case 8:
            this.scrollUp(distance);
            break;
        }
    };

    updateEvents(): void {
        this.events().forEach(function(event) {
            event.update();
        });
        this._commonEvents.forEach(function(event) {
            event.update();
        });
    };

    updateVehicles(): void {
        this._vehicles.forEach(function(vehicle) {
            vehicle.update();
        });
    };

    updateParallax(): void {
        if (this._parallaxLoopX) {
            this._parallaxX += this._parallaxSx / this.tileWidth() / 2;
        }
        if (this._parallaxLoopY) {
            this._parallaxY += this._parallaxSy / this.tileHeight() / 2;
        }
    };

    changeTileset(tilesetId: number): void {
        this._tilesetId = tilesetId;
        this.refresh();
    };

    changeBattleback(battleback1Name: string, battleback2Name: string): void {
        this._battleback1Name = battleback1Name;
        this._battleback2Name = battleback2Name;
    };

    changeParallax(name: string, loopX: boolean, loopY: boolean, sx: number, sy: number): void {
        this._parallaxName = name;
        this._parallaxZero = ImageManager.isZeroParallax(this._parallaxName);
        if (this._parallaxLoopX && !loopX) {
            this._parallaxX = 0;
        }
        if (this._parallaxLoopY && !loopY) {
            this._parallaxY = 0;
        }
        this._parallaxLoopX = loopX;
        this._parallaxLoopY = loopY;
        this._parallaxSx = sx;
        this._parallaxSy = sy;
    };

    updateInterpreter(): void {
        for (;;) {
            this._interpreter.update();
            if (this._interpreter.isRunning()) {
                return;
            }
            if (this._interpreter.eventId() > 0) {
                this.unlockEvent(this._interpreter.eventId());
                this._interpreter.clear();
            }
            if (!this.setupStartingEvent()) {
                return;
            }
        }
    };

    unlockEvent(eventId: number): void {
        if (this._events[eventId]) {
            this._events[eventId].unlock();
        }
    };

    setupStartingEvent(): boolean {
        this.refreshIfNeeded();
        if (this._interpreter.setupReservedCommonEvent()) {
            return true;
        }
        if (this.setupTestEvent()) {
            return true;
        }
        if (this.setupStartingMapEvent()) {
            return true;
        }
        if (this.setupAutorunCommonEvent()) {
            return true;
        }
        return false;
    };

    setupTestEvent(): boolean {
        if ($testEvent) {
            this._interpreter.setup($testEvent, 0);
            $testEvent = null;
            return true;
        }
        return false;
    };

    setupStartingMapEvent(): boolean {
        let events = this.events();
        for (let i = 0; i < events.length; i++) {
            let event = events[i];
            if (event.isStarting()) {
                event.clearStartingFlag();
                this._interpreter.setup(event.list(), event.eventId());
                return true;
            }
        }
        return false;
    };

    setupAutorunCommonEvent(): boolean {
        for (let i = 0; i < $dataCommonEvents.length; i++) {
            let event = $dataCommonEvents[i];
            if (event && event.trigger === 1 && $gameSwitches.value(event.switchId)) {
                this._interpreter.setup(event.list);
                return true;
            }
        }
        return false;
    };

    isAnyEventStarting(): boolean {
        return this.events().some(function(event) {
            return event.isStarting();
        });
    };
}

//-----------------------------------------------------------------------------
// Game_CommonEvent
//
// The game object class for a common event. It contains functionality for
// running parallel process events.

class Game_CommonEvent {
    constructor(commonEventId: number){
        this.initialize(commonEventId);
    }

    initialize(commonEventId: number): void {
        this._commonEventId = commonEventId;
        this.refresh();
    };

    _commonEventId: number;

    event(): RPGMakerMV.DataCommonEvent {
        return $dataCommonEvents[this._commonEventId];
    };

    list(): RPGMakerMV.EventCommand[] {
        return this.event().list;
    };

    refresh(): void {
        if (this.isActive()) {
            if (!this._interpreter) {
                this._interpreter = new Game_Interpreter();
            }
        } else {
            this._interpreter = null;
        }
    };

    _interpreter: Game_Interpreter;

    isActive(): boolean {
        var event = this.event();
        return event.trigger === 2 && $gameSwitches.value(event.switchId);
    };

    update(): void {
        if (this._interpreter) {
            if (!this._interpreter.isRunning()) {
                this._interpreter.setup(this.list());
            }
            this._interpreter.update();
        }
    };
}

//-----------------------------------------------------------------------------
// Game_CharacterBase
//
// The superclass of Game_Character. It handles basic information, such as
// coordinates and images, shared by all characters.

class Game_CharacterBase {
    constructor(){
        this.initialize.apply(this, arguments);
    }

    get x():number {
        return this._x;
    }

    get y():number {
        return this._y;
    }

    //x: number;
    //y: number;

    initialize(): void {
        this.initMembers();
    };

    initMembers(): void {
        this._x = 0;
        this._y = 0;
        this._realX = 0;
        this._realY = 0;
        this._moveSpeed = 4;
        this._moveFrequency = 6;
        this._opacity = 255;
        this._blendMode = 0;
        this._direction = 2;
        this._pattern = 1;
        this._priorityType = 1;
        this._tileId = 0;
        this._characterName = '';
        this._characterIndex = 0;
        this._isObjectCharacter = false;
        this._walkAnime = true;
        this._stepAnime = false;
        this._directionFix = false;
        this._through = false;
        this._transparent = false;
        this._bushDepth = 0;
        this._animationId = 0;
        this._balloonId = 0;
        this._animationPlaying = false;
        this._balloonPlaying = false;
        this._animationCount = 0;
        this._stopCount = 0;
        this._jumpCount = 0;
        this._jumpPeak = 0;
        this._movementSuccess = true;
    };

    _x: number;
    _y: number;
    _realX: number;
    _realY: number;
    _moveSpeed: number;
    _moveFrequency: number;
    _opacity: number;
    _blendMode: number;
    _direction: number;
    _pattern: number;
    _priorityType: number;
    _tileId: number;
    _characterName: string;
    _characterIndex: number;
    _isObjectCharacter: boolean;
    _walkAnime: boolean;
    _stepAnime: boolean;
    _directionFix: boolean;
    _through: boolean;
    _transparent: boolean;
    _bushDepth: number;
    _animationId: number;
    _balloonId: number;
    _animationPlaying: boolean;
    _balloonPlaying: boolean;
    _animationCount: number;
    _stopCount: number;
    _jumpCount: number;
    _jumpPeak: number;
    _movementSuccess: boolean;

    pos(x: number, y: number): boolean {
        return this._x === x && this._y === y;
    };

    posNt(x: number, y: number): boolean {
        // No through
        return this.pos(x, y) && !this.isThrough();
    };

    moveSpeed(): number {
        return this._moveSpeed;
    };

    setMoveSpeed(moveSpeed: number): void {
        this._moveSpeed = moveSpeed;
    };

    moveFrequency(): number {
        return this._moveFrequency;
    };

    setMoveFrequency(moveFrequency: number): void {
        this._moveFrequency = moveFrequency;
    };

    opacity(): number {
        return this._opacity;
    };

    setOpacity(opacity: number): void {
        this._opacity = opacity;
    };

    blendMode(): number {
        return this._blendMode;
    };

    setBlendMode(blendMode: number): void {
        this._blendMode = blendMode;
    };

    isNormalPriority(): boolean {
        return this._priorityType === 1;
    };

    setPriorityType(priorityType: number): void {
        this._priorityType = priorityType;
    };

    isMoving(): boolean {
        return this._realX !== this._x || this._realY !== this._y;
    };

    isJumping(): boolean {
        return this._jumpCount > 0;
    };

    jumpHeight(): number {
        return (this._jumpPeak * this._jumpPeak -
                Math.pow(Math.abs(this._jumpCount - this._jumpPeak), 2)) / 2;
    };

    isStopping(): boolean {
        return !this.isMoving() && !this.isJumping();
    };

    checkStop(threshold: number): boolean {
        return this._stopCount > threshold;
    };

    resetStopCount(): void {
        this._stopCount = 0;
    };

    realMoveSpeed(): number {
        return this._moveSpeed + (this.isDashing() ? 1 : 0);
    };

    distancePerFrame(): number {
        return Math.pow(2, this.realMoveSpeed()) / 256;
    };

    isDashing(): boolean {
        return false;
    };

    isDebugThrough(): boolean {
        return false;
    };

    straighten(): void {
        if (this.hasWalkAnime() || this.hasStepAnime()) {
            this._pattern = 1;
        }
        this._animationCount = 0;
    };

    reverseDir(d: number): number {
        return 10 - d;
    };

    canPass(x: number, y: number, d: number): boolean {
        let x2 = $gameMap.roundXWithDirection(x, d);
        let y2 = $gameMap.roundYWithDirection(y, d);
        if (!$gameMap.isValid(x2, y2)) {
            return false;
        }
        if (this.isThrough() || this.isDebugThrough()) {
            return true;
        }
        if (!this.isMapPassable(x, y, d)) {
            return false;
        }
        if (this.isCollidedWithCharacters(x2, y2)) {
            return false;
        }
        return true;
    };

    canPassDiagonally(x: number, y: number, horz: number, vert: number): boolean {
        let x2 = $gameMap.roundXWithDirection(x, horz);
        let y2 = $gameMap.roundYWithDirection(y, vert);
        if (this.canPass(x, y, vert) && this.canPass(x, y2, horz)) {
            return true;
        }
        if (this.canPass(x, y, horz) && this.canPass(x2, y, vert)) {
            return true;
        }
        return false;
    };

    isMapPassable(x: number, y: number, d: number): boolean {
        let x2 = $gameMap.roundXWithDirection(x, d);
        let y2 = $gameMap.roundYWithDirection(y, d);
        let d2 = this.reverseDir(d);
        return $gameMap.isPassable(x, y, d) && $gameMap.isPassable(x2, y2, d2);
    };

    isCollidedWithCharacters(x: number, y: number): boolean {
        return this.isCollidedWithEvents(x, y) || this.isCollidedWithVehicles(x, y);
    };
    
    isCollidedWithEvents(x: number, y: number): boolean{
        let events = $gameMap.eventsXyNt(x, y);
        return events.some((event: { isNormalPriority: () => any; }) => {
            return event.isNormalPriority();
        });
    };

    isCollidedWithVehicles(x: number, y: number): boolean {
        return $gameMap.boat().posNt(x, y) || $gameMap.ship().posNt(x, y);
    };

    setPosition(x: number, y: number): void {
        this._x = Math.round(x);
        this._y = Math.round(y);
        this._realX = x;
        this._realY = y;
    };

    copyPosition(character: Game_CharacterBase): void {
        this._x = character._x;
        this._y = character._y;
        this._realX = character._realX;
        this._realY = character._realY;
        this._direction = character._direction;
    };

    locate(x: number, y: number): void {
        this.setPosition(x, y);
        this.straighten();
        this.refreshBushDepth();
    };

    direction(): number {
        return this._direction;
    };

    setDirection(d: number): void {
        if (!this.isDirectionFixed() && d) {
            this._direction = d;
        }
        this.resetStopCount();
    };

    isTile(): boolean {
        return this._tileId > 0 && this._priorityType === 0;
    };

    isObjectCharacter(): boolean {
        return this._isObjectCharacter;
    };

    shiftY(): number {
        return this.isObjectCharacter() ? 0 : 6;
    };

    scrolledX(): number {
        return $gameMap.adjustX(this._realX);
    };

    scrolledY(): number {
        return $gameMap.adjustY(this._realY);
    };

    screenX(): number {
        let tw = $gameMap.tileWidth();
        return Math.round(this.scrolledX() * tw + tw / 2);
    };

    screenY(): number {
        let th = $gameMap.tileHeight();
        return Math.round(this.scrolledY() * th + th -
                        this.shiftY() - this.jumpHeight());
    };

    screenZ(): number {
        return this._priorityType * 2 + 1;
    };

    isNearTheScreen(): boolean {
        let gw = Graphics.width;
        let gh = Graphics.height;
        let tw = $gameMap.tileWidth();
        let th = $gameMap.tileHeight();
        let px = this.scrolledX() * tw + tw / 2 - gw / 2;
        let py = this.scrolledY() * th + th / 2 - gh / 2;
        return px >= -gw && px <= gw && py >= -gh && py <= gh;
    };

    update(...args:any[]): void {
        if (this.isStopping()) {
            this.updateStop();
        }
        if (this.isJumping()) {
            this.updateJump();
        } else if (this.isMoving()) {
            this.updateMove();
        }
        this.updateAnimation();
    };

    updateStop(): void {
        this._stopCount++;
    };

    updateJump(): void {
        this._jumpCount--;
        this._realX = (this._realX * this._jumpCount + this._x) / (this._jumpCount + 1.0);
        this._realY = (this._realY * this._jumpCount + this._y) / (this._jumpCount + 1.0);
        this.refreshBushDepth();
        if (this._jumpCount === 0) {
            this._realX = this._x = $gameMap.roundX(this._x);
            this._realY = this._y = $gameMap.roundY(this._y);
        }
    };

    updateMove(): void {
        if (this._x < this._realX) {
            this._realX = Math.max(this._realX - this.distancePerFrame(), this._x);
        }
        if (this._x > this._realX) {
            this._realX = Math.min(this._realX + this.distancePerFrame(), this._x);
        }
        if (this._y < this._realY) {
            this._realY = Math.max(this._realY - this.distancePerFrame(), this._y);
        }
        if (this._y > this._realY) {
            this._realY = Math.min(this._realY + this.distancePerFrame(), this._y);
        }
        if (!this.isMoving()) {
            this.refreshBushDepth();
        }
    };

    updateAnimation(): void {
        this.updateAnimationCount();
        if (this._animationCount >= this.animationWait()) {
            this.updatePattern();
            this._animationCount = 0;
        }
    };

    animationWait(): number {
        return (9 - this.realMoveSpeed()) * 3;
    };

    updateAnimationCount(): void {
        if (this.isMoving() && this.hasWalkAnime()) {
            this._animationCount += 1.5;
        } else if (this.hasStepAnime() || !this.isOriginalPattern()) {
            this._animationCount++;
        }
    };

    updatePattern(): void {
        if (!this.hasStepAnime() && this._stopCount > 0) {
            this.resetPattern();
        } else {
            this._pattern = (this._pattern + 1) % this.maxPattern();
        }
    };

    maxPattern(): number {
        return 4;
    };

    pattern(): number {
        return this._pattern < 3 ? this._pattern : 1;
    };

    setPattern(pattern: number): void {
        this._pattern = pattern;
    };

    isOriginalPattern(): boolean {
        return this.pattern() === 1;
    };

    resetPattern(): void {
        this.setPattern(1);
    };

    refreshBushDepth(): void {
        if (this.isNormalPriority() && !this.isObjectCharacter() &&
                this.isOnBush() && !this.isJumping()) {
            if (!this.isMoving()) {
                this._bushDepth = 12;
            }
        } else {
            this._bushDepth = 0;
        }
    };

    isOnLadder(): boolean {
        return $gameMap.isLadder(this._x, this._y);
    };

    isOnBush(): boolean {
        return $gameMap.isBush(this._x, this._y);
    };

    terrainTag(): boolean {
        return $gameMap.terrainTag(this._x, this._y);
    };

    regionId(): boolean|any {
        return $gameMap.regionId(this._x, this._y);
    };

    increaseSteps(): void {
        if (this.isOnLadder()) {
            this.setDirection(8);
        }
        this.resetStopCount();
        this.refreshBushDepth();
    };

    tileId(): number {
        return this._tileId;
    };

    characterName(): string {
        return this._characterName;
    };

    characterIndex(): number {
        return this._characterIndex;
    };

    setImage(characterName: string, characterIndex: number): void {
        this._tileId = 0;
        this._characterName = characterName;
        this._characterIndex = characterIndex;
        this._isObjectCharacter = ImageManager.isObjectCharacter(characterName);
    };

    setTileImage(tileId: number): void {
        this._tileId = tileId;
        this._characterName = '';
        this._characterIndex = 0;
        this._isObjectCharacter = true;
    };

    checkEventTriggerTouchFront(d: number): void {
        let x2 = $gameMap.roundXWithDirection(this._x, d);
        let y2 = $gameMap.roundYWithDirection(this._y, d);
        this.checkEventTriggerTouch(x2, y2);
    };

    checkEventTriggerTouch(x: number, y: number): boolean {
        return false;
    };
    isMovementSucceeded(): boolean {
        return this._movementSuccess;
    };
    setMovementSuccess(success: boolean): void {
        this._movementSuccess = success;
    };
    moveStraight(d: number): void {
        this.setMovementSuccess(this.canPass(this._x, this._y, d));
        if (this.isMovementSucceeded()) {
            this.setDirection(d);
            this._x = $gameMap.roundXWithDirection(this._x, d);
            this._y = $gameMap.roundYWithDirection(this._y, d);
            this._realX = $gameMap.xWithDirection(this._x, this.reverseDir(d));
            this._realY = $gameMap.yWithDirection(this._y, this.reverseDir(d));
            this.increaseSteps();
        } else {
            this.setDirection(d);
            this.checkEventTriggerTouchFront(d);
        }
    };
    moveDiagonally(horz: number, vert: number): void {
        this.setMovementSuccess(this.canPassDiagonally(this._x, this._y, horz, vert));
        if (this.isMovementSucceeded()) {
            this._x = $gameMap.roundXWithDirection(this._x, horz);
            this._y = $gameMap.roundYWithDirection(this._y, vert);
            this._realX = $gameMap.xWithDirection(this._x, this.reverseDir(horz));
            this._realY = $gameMap.yWithDirection(this._y, this.reverseDir(vert));
            this.increaseSteps();
        }
        if (this._direction === this.reverseDir(horz)) {
            this.setDirection(horz);
        }
        if (this._direction === this.reverseDir(vert)) {
            this.setDirection(vert);
        }
    };
    jump(xPlus: number, yPlus: number): void {
        if (Math.abs(xPlus) > Math.abs(yPlus)) {
            if (xPlus !== 0) {
                this.setDirection(xPlus < 0 ? 4 : 6);
            }
        } else {
            if (yPlus !== 0) {
                this.setDirection(yPlus < 0 ? 8 : 2);
            }
        }
        this._x += xPlus;
        this._y += yPlus;
        var distance = Math.round(Math.sqrt(xPlus * xPlus + yPlus * yPlus));
        this._jumpPeak = 10 + distance - this._moveSpeed;
        this._jumpCount = this._jumpPeak * 2;
        this.resetStopCount();
        this.straighten();
    };
    hasWalkAnime(): boolean {
        return this._walkAnime;
    };
    setWalkAnime(walkAnime: boolean): void {
        this._walkAnime = walkAnime;
    };
    hasStepAnime(): boolean {
        return this._stepAnime;
    };
    setStepAnime(stepAnime: boolean): void {
        this._stepAnime = stepAnime;
    };
    isDirectionFixed(): boolean {
        return this._directionFix;
    };
    setDirectionFix(directionFix: boolean): void {
        this._directionFix = directionFix;
    };
    isThrough(): boolean {
        return this._through;
    };
    setThrough(through: boolean): void {
        this._through = through;
    };
    isTransparent(): boolean {
        return this._transparent;
    };
    bushDepth(): number {
        return this._bushDepth;
    };
    setTransparent(transparent: boolean): void {
        this._transparent = transparent;
    };
    requestAnimation(animationId: number): void {
        this._animationId = animationId;
    };
    requestBalloon(balloonId: number): void {
        this._balloonId = balloonId;
    };
    animationId(): number {
        return this._animationId;
    };
    balloonId(): number {
        return this._balloonId;
    };
    startAnimation(): void {
        this._animationId = 0;
        this._animationPlaying = true;
    };
    startBalloon(): void {
        this._balloonId = 0;
        this._balloonPlaying = true;
    };
    isAnimationPlaying(): boolean {
        return this._animationId > 0 || this._animationPlaying;
    };
    isBalloonPlaying(): boolean {
        return this._balloonId > 0 || this._balloonPlaying;
    };
    endAnimation(): void {
        this._animationPlaying = false;
    };
    endBalloon(): void {
        this._balloonPlaying = false;
    };
}

//-----------------------------------------------------------------------------
// Game_Character
//
// The superclass of Game_Player, Game_Follower, GameVehicle, and Game_Event.

  class Game_Character extends Game_CharacterBase {
    constructor(){
        super();
        this.initialize();
    }
    static ROUTE_END: 0;
    static ROUTE_MOVE_DOWN: 1;
    static ROUTE_MOVE_LEFT: 2;
    static ROUTE_MOVE_RIGHT: 3;
    static ROUTE_MOVE_UP: 4;
    static ROUTE_MOVE_LOWER_L: 5;
    static ROUTE_MOVE_LOWER_R: 6;
    static ROUTE_MOVE_UPPER_L: 7;
    static ROUTE_MOVE_UPPER_R: 8;
    static ROUTE_MOVE_RANDOM: 9;
    static ROUTE_MOVE_TOWARD: 10;
    static ROUTE_MOVE_AWAY: 11;
    static ROUTE_MOVE_FORWARD: 12;
    static ROUTE_MOVE_BACKWARD: 13;
    static ROUTE_JUMP: 14;
    static ROUTE_WAIT: 15;
    static ROUTE_TURN_DOWN: 16;
    static ROUTE_TURN_LEFT: 17;
    static ROUTE_TURN_RIGHT: 18;
    static ROUTE_TURN_UP: 19;
    static ROUTE_TURN_90D_R: 20;
    static ROUTE_TURN_90D_L: 21;
    static ROUTE_TURN_180D: 22;
    static ROUTE_TURN_90D_R_L: 23;
    static ROUTE_TURN_RANDOM: 24;
    static ROUTE_TURN_TOWARD: 25;
    static ROUTE_TURN_AWAY: 26;
    static ROUTE_SWITCH_ON: 27;
    static ROUTE_SWITCH_OFF: 28;
    static ROUTE_CHANGE_SPEED: 29;
    static ROUTE_CHANGE_FREQ: 30;
    static ROUTE_WALK_ANIME_ON: 31;
    static ROUTE_WALK_ANIME_OFF: 32;
    static ROUTE_STEP_ANIME_ON: 33;
    static ROUTE_STEP_ANIME_OFF: 34;
    static ROUTE_DIR_FIX_ON: 35;
    static ROUTE_DIR_FIX_OFF: 36;
    static ROUTE_THROUGH_ON: 37;
    static ROUTE_THROUGH_OFF: 38;
    static ROUTE_TRANSPARENT_ON: 39;
    static ROUTE_TRANSPARENT_OFF: 40;
    static ROUTE_CHANGE_IMAGE: 41;
    static ROUTE_CHANGE_OPACITY: 42;
    static ROUTE_CHANGE_BLEND_MODE: 43;
    static ROUTE_PLAY_SE: 44;
    static ROUTE_SCRIPT: 45;

    initialize(): void {
        Game_CharacterBase.prototype.initialize.call(this);
    };
    initMembers(): void {
        Game_CharacterBase.prototype.initMembers.call(this);
        this._moveRouteForcing = false;
        this._moveRoute = null;
        this._moveRouteIndex = 0;
        this._originalMoveRoute = null;
        this._originalMoveRouteIndex = 0;
        this._waitCount = 0;
    };
    _moveRouteForcing: boolean;
    _moveRoute: RPGMakerMV.MoveRoute;
    _moveRouteIndex: number;
    _originalMoveRoute: RPGMakerMV.MoveRoute;
    _originalMoveRouteIndex: number;
    _waitCount: number;
    _callerEventInfo: RPGMakerMV.EventInfo;

    memorizeMoveRoute(): void {
        this._originalMoveRoute = this._moveRoute;
        this._originalMoveRouteIndex = this._moveRouteIndex;
    }
    restoreMoveRoute(): void {
        this._moveRoute = this._originalMoveRoute;
        this._moveRouteIndex = this._originalMoveRouteIndex;
        this._originalMoveRoute = null;
    }
    isMoveRouteForcing(): boolean {
        return this._moveRouteForcing;
    };
    setMoveRoute(moveRoute: RPGMakerMV.MoveRoute): void {
        this._moveRoute = moveRoute;
        this._moveRouteIndex = 0;
        this._moveRouteForcing = false;
    };
    forceMoveRoute(moveRoute: RPGMakerMV.MoveRoute): void {
        if (!this._originalMoveRoute) {
            this.memorizeMoveRoute();
        }
        this._moveRoute = moveRoute;
        this._moveRouteIndex = 0;
        this._moveRouteForcing = true;
        this._waitCount = 0;
    };
    updateStop(): void {
        Game_CharacterBase.prototype.updateStop.call(this);
        if (this._moveRouteForcing) {
            this.updateRoutineMove();
        }
    };
    updateRoutineMove(): void {
        if (this._waitCount > 0) {
            this._waitCount--;
        } else {
            this.setMovementSuccess(true);
            var command = this._moveRoute.list[this._moveRouteIndex];
            if (command) {
                this.processMoveCommand(command);
                this.advanceMoveRouteIndex();
            }
        }
    };
    processMoveCommand(command: RPGMakerMV.MoveCommand): void {
        let gc = Game_Character;
        let params:any = command.parameters;
        switch (command.code) {
        case gc.ROUTE_END:
            this.processRouteEnd();
            break;
        case gc.ROUTE_MOVE_DOWN:
            this.moveStraight(2);
            break;
        case gc.ROUTE_MOVE_LEFT:
            this.moveStraight(4);
            break;
        case gc.ROUTE_MOVE_RIGHT:
            this.moveStraight(6);
            break;
        case gc.ROUTE_MOVE_UP:
            this.moveStraight(8);
            break;
        case gc.ROUTE_MOVE_LOWER_L:
            this.moveDiagonally(4, 2);
            break;
        case gc.ROUTE_MOVE_LOWER_R:
            this.moveDiagonally(6, 2);
            break;
        case gc.ROUTE_MOVE_UPPER_L:
            this.moveDiagonally(4, 8);
            break;
        case gc.ROUTE_MOVE_UPPER_R:
            this.moveDiagonally(6, 8);
            break;
        case gc.ROUTE_MOVE_RANDOM:
            this.moveRandom();
            break;
        case gc.ROUTE_MOVE_TOWARD:
            this.moveTowardPlayer();
            break;
        case gc.ROUTE_MOVE_AWAY:
            this.moveAwayFromPlayer();
            break;
        case gc.ROUTE_MOVE_FORWARD:
            this.moveForward();
            break;
        case gc.ROUTE_MOVE_BACKWARD:
            this.moveBackward();
            break;
        case gc.ROUTE_JUMP:
            this.jump(params[0], params[1]);
            break;
        case gc.ROUTE_WAIT:
            this._waitCount = params[0] - 1;
            break;
        case gc.ROUTE_TURN_DOWN:
            this.setDirection(2);
            break;
        case gc.ROUTE_TURN_LEFT:
            this.setDirection(4);
            break;
        case gc.ROUTE_TURN_RIGHT:
            this.setDirection(6);
            break;
        case gc.ROUTE_TURN_UP:
            this.setDirection(8);
            break;
        case gc.ROUTE_TURN_90D_R:
            this.turnRight90();
            break;
        case gc.ROUTE_TURN_90D_L:
            this.turnLeft90();
            break;
        case gc.ROUTE_TURN_180D:
            this.turn180();
            break;
        case gc.ROUTE_TURN_90D_R_L:
            this.turnRightOrLeft90();
            break;
        case gc.ROUTE_TURN_RANDOM:
            this.turnRandom();
            break;
        case gc.ROUTE_TURN_TOWARD:
            this.turnTowardPlayer();
            break;
        case gc.ROUTE_TURN_AWAY:
            this.turnAwayFromPlayer();
            break;
        case gc.ROUTE_SWITCH_ON:
            $gameSwitches.setValue(params[0], true);
            break;
        case gc.ROUTE_SWITCH_OFF:
            $gameSwitches.setValue(params[0], false);
            break;
        case gc.ROUTE_CHANGE_SPEED:
            this.setMoveSpeed(params[0]);
            break;
        case gc.ROUTE_CHANGE_FREQ:
            this.setMoveFrequency(params[0]);
            break;
        case gc.ROUTE_WALK_ANIME_ON:
            this.setWalkAnime(true);
            break;
        case gc.ROUTE_WALK_ANIME_OFF:
            this.setWalkAnime(false);
            break;
        case gc.ROUTE_STEP_ANIME_ON:
            this.setStepAnime(true);
            break;
        case gc.ROUTE_STEP_ANIME_OFF:
            this.setStepAnime(false);
            break;
        case gc.ROUTE_DIR_FIX_ON:
            this.setDirectionFix(true);
            break;
        case gc.ROUTE_DIR_FIX_OFF:
            this.setDirectionFix(false);
            break;
        case gc.ROUTE_THROUGH_ON:
            this.setThrough(true);
            break;
        case gc.ROUTE_THROUGH_OFF:
            this.setThrough(false);
            break;
        case gc.ROUTE_TRANSPARENT_ON:
            this.setTransparent(true);
            break;
        case gc.ROUTE_TRANSPARENT_OFF:
            this.setTransparent(false);
            break;
        case gc.ROUTE_CHANGE_IMAGE:
            this.setImage(params[0], params[1]);
            break;
        case gc.ROUTE_CHANGE_OPACITY:
            this.setOpacity(params[0]);
            break;
        case gc.ROUTE_CHANGE_BLEND_MODE:
            this.setBlendMode(params[0]);
            break;
        case gc.ROUTE_PLAY_SE:
            AudioManager.playSe(params[0]);
            break;
        case gc.ROUTE_SCRIPT:
            eval(params[0]);
            break;
        }
    };
    deltaXFrom(x: number): number {
        return $gameMap.deltaX(this.x, x);
    };
    deltaYFrom(y: number): number {
        return $gameMap.deltaY(this.y, y);
    };
    moveRandom(): void {
        var d = 2 + Math.randomInt(4) * 2;
        if (this.canPass(this.x, this.y, d)) {
            this.moveStraight(d);
        }
    };
    moveTowardCharacter(character: Game_CharacterBase): void {
        var sx = this.deltaXFrom(character.x);
        var sy = this.deltaYFrom(character.y);
        if (Math.abs(sx) > Math.abs(sy)) {
            this.moveStraight(sx > 0 ? 4 : 6);
            if (!this.isMovementSucceeded() && sy !== 0) {
                this.moveStraight(sy > 0 ? 8 : 2);
            }
        } else if (sy !== 0) {
            this.moveStraight(sy > 0 ? 8 : 2);
            if (!this.isMovementSucceeded() && sx !== 0) {
                this.moveStraight(sx > 0 ? 4 : 6);
            }
        }
    };
    moveAwayFromCharacter(character: Game_CharacterBase): void {
        var sx = this.deltaXFrom(character.x);
        var sy = this.deltaYFrom(character.y);
        if (Math.abs(sx) > Math.abs(sy)) {
            this.moveStraight(sx > 0 ? 6 : 4);
            if (!this.isMovementSucceeded() && sy !== 0) {
                this.moveStraight(sy > 0 ? 2 : 8);
            }
        } else if (sy !== 0) {
            this.moveStraight(sy > 0 ? 2 : 8);
            if (!this.isMovementSucceeded() && sx !== 0) {
                this.moveStraight(sx > 0 ? 6 : 4);
            }
        }
    };
    turnTowardCharacter(character: Game_CharacterBase): void {
        var sx = this.deltaXFrom(character.x);
        var sy = this.deltaYFrom(character.y);
        if (Math.abs(sx) > Math.abs(sy)) {
            this.setDirection(sx > 0 ? 4 : 6);
        } else if (sy !== 0) {
            this.setDirection(sy > 0 ? 8 : 2);
        }
    };
    turnAwayFromCharacter(character: Game_CharacterBase): void {
        var sx = this.deltaXFrom(character.x);
        var sy = this.deltaYFrom(character.y);
        if (Math.abs(sx) > Math.abs(sy)) {
            this.setDirection(sx > 0 ? 6 : 4);
        } else if (sy !== 0) {
            this.setDirection(sy > 0 ? 2 : 8);
        }
    };
    turnTowardPlayer(): void {
        this.turnTowardCharacter($gamePlayer);
    };
    turnAwayFromPlayer(): void {
        this.turnAwayFromCharacter($gamePlayer);
    };
    moveTowardPlayer(): void {
        this.moveTowardCharacter($gamePlayer);
    };
    moveAwayFromPlayer(): void {
        this.moveAwayFromCharacter($gamePlayer);
    };
    moveForward(): void {
        this.moveStraight(this.direction());
    };
    moveBackward(): void {
        var lastDirectionFix = this.isDirectionFixed();
        this.setDirectionFix(true);
        this.moveStraight(this.reverseDir(this.direction()));
        this.setDirectionFix(lastDirectionFix);
    };
    processRouteEnd(): void {
        if (this._moveRoute.repeat) {
            this._moveRouteIndex = -1;
        } else if (this._moveRouteForcing) {
            this._moveRouteForcing = false;
            this.restoreMoveRoute();
        }
    };
    advanceMoveRouteIndex(): void {
        var moveRoute = this._moveRoute;
        if (moveRoute && (this.isMovementSucceeded() || moveRoute.skippable)) {
            var numCommands = moveRoute.list.length - 1;
            this._moveRouteIndex++;
            if (moveRoute.repeat && this._moveRouteIndex >= numCommands) {
                this._moveRouteIndex = 0;
            }
        }
    };
    turnRight90(): void {
        switch (this.direction()) {
        case 2:
            this.setDirection(4);
            break;
        case 4:
            this.setDirection(8);
            break;
        case 6:
            this.setDirection(2);
            break;
        case 8:
            this.setDirection(6);
            break;
        }
    };
    turnLeft90(): void {
        switch (this.direction()) {
        case 2:
            this.setDirection(6);
            break;
        case 4:
            this.setDirection(2);
            break;
        case 6:
            this.setDirection(8);
            break;
        case 8:
            this.setDirection(4);
            break;
        }
    };
    turn180(): void {
        this.setDirection(this.reverseDir(this.direction()));
    };
    turnRightOrLeft90(): void {
        switch (Math.randomInt(2)) {
        case 0:
            this.turnRight90();
            break;
        case 1:
            this.turnLeft90();
            break;
        }
    };
    turnRandom(): void {
        this.setDirection(2 + Math.randomInt(4) * 2);
    };

    swap(character:any):void {
        let newX = character.x;
        let newY = character.y;
        character.locate(this.x, this.y);
        this.locate(newX, newY);
    };

    findDirectionTo(goalX: number, goalY: number): number {
        let searchLimit = this.searchLimit();
        let mapWidth = $gameMap.width();
        let nodeList = [];
        let openList = [];
        let closedList = [];
        let start:any = {};
        let best = start;
    
        if (this.x === goalX && this.y === goalY) {
            return 0;
        }
    
        start.parent = null;
        start.x = this.x;
        start.y = this.y;
        start.g = 0;
        start.f = $gameMap.distance(start.x, start.y, goalX, goalY);
        nodeList.push(start);
        openList.push(start.y * mapWidth + start.x);
    
        while (nodeList.length > 0) {
            var bestIndex = 0;
            for (var i = 0; i < nodeList.length; i++) {
                if (nodeList[i].f < nodeList[bestIndex].f) {
                    bestIndex = i;
                }
            }
    
            var current = nodeList[bestIndex];
            var x1 = current.x;
            var y1 = current.y;
            var pos1 = y1 * mapWidth + x1;
            var g1 = current.g;
    
            nodeList.splice(bestIndex, 1);
            openList.splice(openList.indexOf(pos1), 1);
            closedList.push(pos1);
    
            if (current.x === goalX && current.y === goalY) {
                best = current;
                break;
            }
    
            if (g1 >= searchLimit) {
                continue;
            }
    
            for (var j = 0; j < 4; j++) {
                var direction = 2 + j * 2;
                var x2 = $gameMap.roundXWithDirection(x1, direction);
                var y2 = $gameMap.roundYWithDirection(y1, direction);
                var pos2 = y2 * mapWidth + x2;
    
                if (closedList.contains(pos2)) {
                    continue;
                }
                if (!this.canPass(x1, y1, direction)) {
                    continue;
                }
    
                var g2 = g1 + 1;
                var index2 = openList.indexOf(pos2);
    
                if (index2 < 0 || g2 < nodeList[index2].g) {
                    var neighbor;
                    if (index2 >= 0) {
                        neighbor = nodeList[index2];
                    } else {
                        neighbor = {};
                        nodeList.push(neighbor);
                        openList.push(pos2);
                    }
                    neighbor.parent = current;
                    neighbor.x = x2;
                    neighbor.y = y2;
                    neighbor.g = g2;
                    neighbor.f = g2 + $gameMap.distance(x2, y2, goalX, goalY);
                    if (!best || neighbor.f - neighbor.g < best.f - best.g) {
                        best = neighbor;
                    }
                }
            }
        }
    
        var node = best;
        while (node.parent && node.parent !== start) {
            node = node.parent;
        }
    
        var deltaX1 = $gameMap.deltaX(node.x, start.x);
        var deltaY1 = $gameMap.deltaY(node.y, start.y);
        if (deltaY1 > 0) {
            return 2;
        } else if (deltaX1 < 0) {
            return 4;
        } else if (deltaX1 > 0) {
            return 6;
        } else if (deltaY1 < 0) {
            return 8;
        }
    
        var deltaX2 = this.deltaXFrom(goalX);
        var deltaY2 = this.deltaYFrom(goalY);
        if (Math.abs(deltaX2) > Math.abs(deltaY2)) {
            return deltaX2 > 0 ? 4 : 6;
        } else if (deltaY2 !== 0) {
            return deltaY2 > 0 ? 8 : 2;
        }
    
        return 0;
    };
    searchLimit(): number {
        return 12;
    };
}

//-----------------------------------------------------------------------------
// Game_Player
//
// The game object class for the player. It contains event starting
// determinants and map scrolling functions.

 class Game_Player extends Game_Character {
    constructor(){
        super()
        this.initialize();
    }
    initialize(): void {
        Game_Character.prototype.initialize.call(this);
        this.setTransparent($dataSystem.optTransparent);
    };

    initMembers(): void {
        Game_Character.prototype.initMembers.call(this);
        this._vehicleType = 'walk';
        this._vehicleGettingOn = false;
        this._vehicleGettingOff = false;
        this._dashing = false;
        this._needsMapReload = false;
        this._transferring = false;
        this._newMapId = 0;
        this._newX = 0;
        this._newY = 0;
        this._newDirection = 0;
        this._fadeType = 0;
        this._followers = new Game_Followers();
        this._encounterCount = 0;
    };
    _vehicleType: string;
    _vehicleGettingOn: boolean;
    _vehicleGettingOff: boolean;
    _dashing: boolean;
    _needsMapReload: boolean;
    _transferring: boolean;
    _newMapId: number;
    _newX: number;
    _newY: number;
    _newDirection: number;
    _fadeType: number;
    _followers: Game_Followers;
    _encounterCount: number;

    clearTransferInfo(): void {
        this._transferring = false;
        this._newMapId = 0;
        this._newX = 0;
        this._newY = 0;
        this._newDirection = 0;
    };
    followers(): Game_Followers {
        return this._followers;
    };
    refresh(): void {
        var actor = $gameParty.leader();
        var characterName = actor ? actor.characterName() : '';
        var characterIndex = actor ? actor.characterIndex() : 0;
        this.setImage(characterName, characterIndex);
        this._followers.refresh();
    };
    isStopping(): boolean {
        if (this._vehicleGettingOn || this._vehicleGettingOff) {
            return false;
        }
        return Game_Character.prototype.isStopping.call(this);
    };
    reserveTransfer(mapId: number, x: number, y: number, d?: number, fadeType?: number): void {
        this._transferring = true;
        this._newMapId = mapId;
        this._newX = x;
        this._newY = y;
        this._newDirection = d;
        this._fadeType = fadeType;
    };
    requestMapReload(): void {
        this._needsMapReload = true;
    };
    isTransferring(): boolean {
        return this._transferring;
    };
    newMapId(): number {
        return this._newMapId;
    };
    fadeType(): number {
        return this._fadeType;
    };
    performTransfer(): void {
        if (this.isTransferring()) {
            this.setDirection(this._newDirection);
            if (this._newMapId !== $gameMap.mapId() || this._needsMapReload) {
                $gameMap.setup(this._newMapId);
                this._needsMapReload = false;
            }
            this.locate(this._newX, this._newY);
            this.refresh();
            this.clearTransferInfo();
        }
    };
    isMapPassable(x: number, y: number, d: number): boolean {
        var vehicle:any = this.vehicle();
        if (vehicle) {
            return vehicle.isMapPassable(x, y, d);
        } else {
            return Game_Character.prototype.isMapPassable.call(this, x, y, d);
        }
    };
    vehicle(): RPGMakerMV.Vehicle|any {
        return $gameMap.vehicle(this._vehicleType);
    };
    isInBoat(): boolean {
        return this._vehicleType === 'boat';
    };
    isInShip(): boolean {
        return this._vehicleType === 'ship';
    };
    isInAirship(): boolean {
        return this._vehicleType === 'airship';
    };
    isInVehicle(): boolean {
        return this.isInBoat() || this.isInShip() || this.isInAirship();
    };
    isNormal(): boolean {
        return this._vehicleType === 'walk' && !this.isMoveRouteForcing();
    };
    isDashing(): boolean {
        return this._dashing;
    };
    isDebugThrough(): boolean {
        return Input.isPressed('control') && $gameTemp.isPlaytest();
    };
    isCollided(x: number, y: number): boolean {
        if (this.isThrough()) {
            return false;
        } else {
            return this.pos(x, y) || this._followers.isSomeoneCollided(x, y);
        }
    };
    centerX(): number {
        return (Graphics.width / $gameMap.tileWidth() - 1) / 2.0;
    };
    centerY(): number {
        return (Graphics.height / $gameMap.tileHeight() - 1) / 2.0;
    };
    center(x: number, y: number): void {
        return $gameMap.setDisplayPos(x - this.centerX(), y - this.centerY());
    };
    locate(x: number, y: number): void {
        Game_Character.prototype.locate.call(this, x, y);
        this.center(x, y);
        this.makeEncounterCount();
        if (this.isInVehicle()) {
            this.vehicle().refresh();
        }
        this._followers.synchronize(x, y, this.direction());
    };
    increaseSteps(): void {
        Game_Character.prototype.increaseSteps.call(this);
        if (this.isNormal()) {
            $gameParty.increaseSteps();
        }
    };
    makeEncounterCount(): void {
        var n = $gameMap.encounterStep();
        this._encounterCount = Math.randomInt(n) + Math.randomInt(n) + 1;
    };
    makeEncounterTroopId(): number {
        var encounterList:any = [];
        var weightSum = 0;
        $gameMap.encounterList().forEach((encounter: RPGMakerMV.Encounter) => {
            if (this.meetsEncounterConditions(encounter)) {
                encounterList.push(encounter);
                weightSum += encounter.weight;
            }
        }, this);
        if (weightSum > 0) {
            var value = Math.randomInt(weightSum);
            for (var i = 0; i < encounterList.length; i++) {
                value -= encounterList[i].weight;
                if (value < 0) {
                    return encounterList[i].troopId;
                }
            }
        }
        return 0;
    };
    meetsEncounterConditions(encounter: RPGMakerMV.Encounter): boolean {
        return (encounter.regionSet.length === 0 ||
                encounter.regionSet.contains(this.regionId()));
    };
    executeEncounter(): boolean {
        if (!$gameMap.isEventRunning() && this._encounterCount <= 0) {
            this.makeEncounterCount();
            var troopId = this.makeEncounterTroopId();
            if ($dataTroops[troopId]) {
                BattleManager.setup(troopId, true, false);
                BattleManager.onEncounter();
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    };
    startMapEvent(x: number, y: number, triggers: number[], normal: boolean): void {
        if (!$gameMap.isEventRunning()) {
            $gameMap.eventsXy(x, y).forEach((event: { isTriggerIn: (arg0: number[]) => any; isNormalPriority: () => boolean; start: () => void; }) => {
                if (event.isTriggerIn(triggers) && event.isNormalPriority() === normal) {
                    event.start();
                }
            });
        }
    };
    moveByInput(): void {
        if (!this.isMoving() && this.canMove()) {
            var direction = this.getInputDirection();
            if (direction > 0) {
                $gameTemp.clearDestination();
            } else if ($gameTemp.isDestinationValid()){
                var x = $gameTemp.destinationX();
                var y = $gameTemp.destinationY();
                direction = this.findDirectionTo(x, y);
            }
            if (direction > 0) {
                this.executeMove(direction);
            }
        }
    };
    canMove(): boolean {
        if ($gameMap.isEventRunning() || $gameMessage.isBusy()) {
            return false;
        }
        if (this.isMoveRouteForcing() || this.areFollowersGathering()) {
            return false;
        }
        if (this._vehicleGettingOn || this._vehicleGettingOff) {
            return false;
        }
        if (this.isInVehicle() && !this.vehicle().canMove()) {
            return false;
        }
        return true;
    };
    getInputDirection(): number {
        return Input.dir4;
    };
    executeMove(direction: number): void {
        this.moveStraight(direction);
    };
   
    update(sceneActive: boolean): void {
        var lastScrolledX = this.scrolledX();
        var lastScrolledY = this.scrolledY();
        var wasMoving = this.isMoving();
        this.updateDashing();
        if (sceneActive) {
            this.moveByInput();
        }
        Game_Character.prototype.update.call(this);
        this.updateScroll(lastScrolledX, lastScrolledY);
        this.updateVehicle();
        if (!this.isMoving()) {
            this.updateNonmoving(wasMoving);
        }
        this._followers.update();
    };
    updateDashing(): void {
        if (this.isMoving()) {
            return;
        }
        if (this.canMove() && !this.isInVehicle() && !$gameMap.isDashDisabled()) {
            this._dashing = this.isDashButtonPressed() || $gameTemp.isDestinationValid();
        } else {
            this._dashing = false;
        }
    };
    isDashButtonPressed(): boolean {
        var shift = Input.isPressed('shift');
        if (ConfigManager.alwaysDash) {
            return !shift;
        } else {
            return shift;
        }
    };
    updateScroll(lastScrolledX: number, lastScrolledY: number): void {
        var x1 = lastScrolledX;
        var y1 = lastScrolledY;
        var x2 = this.scrolledX();
        var y2 = this.scrolledY();
        if (y2 > y1 && y2 > this.centerY()) {
            $gameMap.scrollDown(y2 - y1);
        }
        if (x2 < x1 && x2 < this.centerX()) {
            $gameMap.scrollLeft(x1 - x2);
        }
        if (x2 > x1 && x2 > this.centerX()) {
            $gameMap.scrollRight(x2 - x1);
        }
        if (y2 < y1 && y2 < this.centerY()) {
            $gameMap.scrollUp(y1 - y2);
        }
    };
    updateVehicle(): void {
        if (this.isInVehicle() && !this.areFollowersGathering()) {
            if (this._vehicleGettingOn) {
                this.updateVehicleGetOn();
            } else if (this._vehicleGettingOff) {
                this.updateVehicleGetOff();
            } else {
                this.vehicle().syncWithPlayer();
            }
        }
    };
    updateVehicleGetOn(): void {
        if (!this.areFollowersGathering() && !this.isMoving()) {
            this.setDirection(this.vehicle().direction());
            this.setMoveSpeed(this.vehicle().moveSpeed());
            this._vehicleGettingOn = false;
            this.setTransparent(true);
            if (this.isInAirship()) {
                this.setThrough(true);
            }
            this.vehicle().getOn();
        }
    };
    updateVehicleGetOff(): void {
        if (!this.areFollowersGathering() && this.vehicle().isLowest()) {
            this._vehicleGettingOff = false;
            this._vehicleType = 'walk';
            this.setTransparent(false);
        }
    };
    updateNonmoving(wasMoving: boolean): void {
        if (!$gameMap.isEventRunning()) {
            if (wasMoving) {
                $gameParty.onPlayerWalk();
                this.checkEventTriggerHere([1,2]);
                if ($gameMap.setupStartingEvent()) {
                    return;
                }
            }
            if (this.triggerAction()) {
                return;
            }
            if (wasMoving) {
                this.updateEncounterCount();
            } else {
                $gameTemp.clearDestination();
            }
        }
    };
    triggerAction(): boolean {
        if (this.canMove()) {
            if (this.triggerButtonAction()) {
                return true;
            }
            if (this.triggerTouchAction()) {
                return true;
            }
        }
        return false;
    };
    triggerButtonAction(): boolean {
        if (Input.isTriggered('ok')) {
            if (this.getOnOffVehicle()) {
                return true;
            }
            this.checkEventTriggerHere([0]);
            if ($gameMap.setupStartingEvent()) {
                return true;
            }
            this.checkEventTriggerThere([0,1,2]);
            if ($gameMap.setupStartingEvent()) {
                return true;
            }
        }
        return false;
    };
    triggerTouchAction(): boolean {
        if ($gameTemp.isDestinationValid()){
            var direction = this.direction();
            var x1 = this.x;
            var y1 = this.y;
            var x2 = $gameMap.roundXWithDirection(x1, direction);
            var y2 = $gameMap.roundYWithDirection(y1, direction);
            var x3 = $gameMap.roundXWithDirection(x2, direction);
            var y3 = $gameMap.roundYWithDirection(y2, direction);
            var destX = $gameTemp.destinationX();
            var destY = $gameTemp.destinationY();
            if (destX === x1 && destY === y1) {
                return this.triggerTouchActionD1(x1, y1);
            } else if (destX === x2 && destY === y2) {
                return this.triggerTouchActionD2(x2, y2);
            } else if (destX === x3 && destY === y3) {
                return this.triggerTouchActionD3(x2, y2);
            }
        }
        return false;
    };
    triggerTouchActionD1(x1: number, y1: number): boolean {
        if ($gameMap.airship().pos(x1, y1)) {
            if (TouchInput.isTriggered() && this.getOnOffVehicle()) {
                return true;
            }
        }
        this.checkEventTriggerHere([0]);
        return $gameMap.setupStartingEvent();
    };
    triggerTouchActionD2(x2: number, y2: number): boolean {
        if ($gameMap.boat().pos(x2, y2) || $gameMap.ship().pos(x2, y2)) {
            if (TouchInput.isTriggered() && this.getOnVehicle()) {
                return true;
            }
        }
        if (this.isInBoat() || this.isInShip()) {
            if (TouchInput.isTriggered() && this.getOffVehicle()) {
                return true;
            }
        }
        this.checkEventTriggerThere([0,1,2]);
        return $gameMap.setupStartingEvent();
    };
    triggerTouchActionD3(x2: number, y2: number): boolean {
        if ($gameMap.isCounter(x2, y2)) {
            this.checkEventTriggerThere([0,1,2]);
        }
        return $gameMap.setupStartingEvent();
    };
    updateEncounterCount(): void {
        if (this.canEncounter()) {
            this._encounterCount -= this.encounterProgressValue();
        }
    };
    canEncounter(): boolean {
        return (!$gameParty.hasEncounterNone() && $gameSystem.isEncounterEnabled() &&
                !this.isInAirship() && !this.isMoveRouteForcing() && !this.isDebugThrough());
    };
    encounterProgressValue(): number {
        var value = $gameMap.isBush(this.x, this.y) ? 2 : 1;
        if ($gameParty.hasEncounterHalf()) {
            value *= 0.5;
        }
        if (this.isInShip()) {
            value *= 0.5;
        }
        return value;
    };
    checkEventTriggerHere(triggers: number[]): void {
        if (this.canStartLocalEvents()) {
            this.startMapEvent(this.x, this.y, triggers, false);
        }
    };
    checkEventTriggerThere(triggers: number[]): void {
        if (this.canStartLocalEvents()) {
            var direction = this.direction();
            var x1 = this.x;
            var y1 = this.y;
            var x2 = $gameMap.roundXWithDirection(x1, direction);
            var y2 = $gameMap.roundYWithDirection(y1, direction);
            this.startMapEvent(x2, y2, triggers, true);
            if (!$gameMap.isAnyEventStarting() && $gameMap.isCounter(x2, y2)) {
                var x3 = $gameMap.roundXWithDirection(x2, direction);
                var y3 = $gameMap.roundYWithDirection(y2, direction);
                this.startMapEvent(x3, y3, triggers, true);
            }
        }
    };
    checkEventTriggerTouch(x: number, y: number): boolean|any {
        if (this.canStartLocalEvents()) {
            this.startMapEvent(x, y, [1,2], true);
        }
    };
    //checkEventTriggerTouch(x: number, y: number): void{}
    canStartLocalEvents(): boolean {
        return !this.isInAirship();
    };
    getOnOffVehicle(): boolean {
        if (this.isInVehicle()) {
            return this.getOffVehicle();
        } else {
            return this.getOnVehicle();
        }
    };
    getOnVehicle(): boolean {
        var direction = this.direction();
        var x1 = this.x;
        var y1 = this.y;
        var x2 = $gameMap.roundXWithDirection(x1, direction);
        var y2 = $gameMap.roundYWithDirection(y1, direction);
        if ($gameMap.airship().pos(x1, y1)) {
            this._vehicleType = 'airship';
        } else if ($gameMap.ship().pos(x2, y2)) {
            this._vehicleType = 'ship';
        } else if ($gameMap.boat().pos(x2, y2)) {
            this._vehicleType = 'boat';
        }
        if (this.isInVehicle()) {
            this._vehicleGettingOn = true;
            if (!this.isInAirship()) {
                this.forceMoveForward();
            }
            this.gatherFollowers();
        }
        return this._vehicleGettingOn;
    };
    getOffVehicle(): boolean {
        if (this.vehicle().isLandOk(this.x, this.y, this.direction())) {
            if (this.isInAirship()) {
                this.setDirection(2);
            }
            this._followers.synchronize(this.x, this.y, this.direction());
            this.vehicle().getOff();
            if (!this.isInAirship()) {
                this.forceMoveForward();
                this.setTransparent(false);
            }
            this._vehicleGettingOff = true;
            this.setMoveSpeed(4);
            this.setThrough(false);
            this.makeEncounterCount();
            this.gatherFollowers();
        }
        return this._vehicleGettingOff;
    };
    forceMoveForward(): void {
        this.setThrough(true);
        this.moveForward();
        this.setThrough(false);
    };
    isOnDamageFloor(): boolean {
        return $gameMap.isDamageFloor(this.x, this.y) && !this.isInAirship();
    };
    moveStraight(d:number): void {
        if (this.canPass(this.x, this.y, d)) {
            this._followers.updateMove();
        }
        Game_Character.prototype.moveStraight.call(this, d);
    };
    moveDiagonally(horz:number, vert:number): void {
        if (this.canPassDiagonally(this.x, this.y, horz, vert)) {
            this._followers.updateMove();
        }
        Game_Character.prototype.moveDiagonally.call(this, horz, vert);
    };
    jump(xPlus: number, yPlus: number): void {
        Game_Character.prototype.jump.call(this, xPlus, yPlus);
        this._followers.jumpAll();
    };
    showFollowers(): void {
        this._followers.show();
    };
    hideFollowers(): void {
        this._followers.hide();
    };
    gatherFollowers(): void {
        this._followers.gather();
    };
    areFollowersGathering(): boolean {
        return this._followers.areGathering();
    };
    areFollowersGathered(): boolean {
        return this._followers.areGathered();
    };
}

//-----------------------------------------------------------------------------
// Game_Follower
//
// The game object class for a follower. A follower is an allied character,
// other than the front character, displayed in the party.

class Game_Follower extends Game_Character {
    constructor(i?:number){ 
        super();
        this.initialize.apply(this, arguments);
    }
    initialize(memberIndex?: number): void {
        Game_Character.prototype.initialize.call(this);
        this._memberIndex = memberIndex;
        this.setTransparent($dataSystem.optTransparent);
        this.setThrough(true);
    };
    _memberIndex: number;

    refresh(): void {
        var characterName = this.isVisible() ? this.actor().characterName() : '';
        var characterIndex = this.isVisible() ? this.actor().characterIndex() : 0;
        this.setImage(characterName, characterIndex);
    };
    actor(): Game_Actor {
        return $gameParty.battleMembers()[this._memberIndex];
    };
    isVisible(): boolean {
        return this.actor() && $gamePlayer.followers().isVisible();
    };
    update(): void {
        Game_Character.prototype.update.call(this);
        this.setMoveSpeed($gamePlayer.realMoveSpeed());
        this.setOpacity($gamePlayer.opacity());
        this.setBlendMode($gamePlayer.blendMode());
        this.setWalkAnime($gamePlayer.hasWalkAnime());
        this.setStepAnime($gamePlayer.hasStepAnime());
        this.setDirectionFix($gamePlayer.isDirectionFixed());
        this.setTransparent($gamePlayer.isTransparent());
    };
    chaseCharacter(character: Game_CharacterBase): void {
        var sx = this.deltaXFrom(character.x);
        var sy = this.deltaYFrom(character.y);
        if (sx !== 0 && sy !== 0) {
            this.moveDiagonally(sx > 0 ? 4 : 6, sy > 0 ? 8 : 2);
        } else if (sx !== 0) {
            this.moveStraight(sx > 0 ? 4 : 6);
        } else if (sy !== 0) {
            this.moveStraight(sy > 0 ? 8 : 2);
        }
        this.setMoveSpeed($gamePlayer.realMoveSpeed());
    };
}

//-----------------------------------------------------------------------------
// Game_Followers
//
// The wrapper class for a follower array.

 class Game_Followers extends Game_Character {
    constructor(){
        super();
        this.initialize.apply(this, arguments);
    }
    initialize(): void {
        this._visible = $dataSystem.optFollowers;
        this._gathering = false;
        this._data = [];
        for (var i = 1; i < $gameParty.maxBattleMembers(); i++) {
            this._data.push(new Game_Follower(i));
        }
    };
    _visible: boolean;
    _gathering: boolean;
    _data: Game_Follower[];

    isVisible(): boolean {
        return this._visible;
    };
    show(): void {
        this._visible = true;
    };
    hide(): void {
        this._visible = false;
    };
    follower(index: number): Game_Follower {
        return this._data[index];
    };
    forEach(callback: Function|any, thisObject?: this|any): void {
        this._data.forEach(callback, thisObject);
    };
    reverseEach(callback: Function|any, thisObject?: this): void {
        this._data.reverse();
        this._data.forEach(callback, thisObject);
        this._data.reverse();
    };
    refresh(): void {
        this.forEach((follower: { refresh: () => any; }) => {
            return follower.refresh();
        }, this);
    };
    update(): void {
        if (this.areGathering()) {
            if (!this.areMoving()) {
                this.updateMove();
            }
            if (this.areGathered()) {
                this._gathering = false;
            }
        }
        this.forEach((follower: { update: () => void; }) => {
            follower.update();
        }, this);
    };
    updateMove(): void {
        for (var i = this._data.length - 1; i >= 0; i--) {
            var precedingCharacter = (i > 0 ? this._data[i - 1] : $gamePlayer);
            this._data[i].chaseCharacter(precedingCharacter);
        }
    };
    jumpAll(): void {
        if ($gamePlayer.isJumping()) {
            for (var i = 0; i < this._data.length; i++) {
                var follower = this._data[i];
                var sx = $gamePlayer.deltaXFrom(follower.x);
                var sy = $gamePlayer.deltaYFrom(follower.y);
                follower.jump(sx, sy);
            }
        }
    };
    synchronize(x: number, y: number, d: number): void {
        this.forEach((follower: { locate: (arg0: number, arg1: number) => void; setDirection: (arg0: number) => void; }) => {
            follower.locate(x, y);
            follower.setDirection(d);
        }, this);
    };
    gather(): void {
        this._gathering = true;
    };
    areGathering(): boolean {
        return this._gathering;
    };
    visibleFollowers(): boolean|any {
        return this._data.filter(follower => {
            return follower.isVisible();
        }, this);
    };
    areMoving(): boolean|any {
        return this.visibleFollowers().some((follower: { isMoving: () => any; }) => {
            return follower.isMoving();
        }, this);
    };
    areGathered(): boolean {
        return this.visibleFollowers().every((follower: { isMoving: () => any; pos: (arg0: number, arg1: number) => any; }) => {
            return !follower.isMoving() && follower.pos($gamePlayer.x, $gamePlayer.y);
        }, this);
    };
    isSomeoneCollided(x: number, y: number): boolean {
        return this.visibleFollowers().some((follower: { pos: (arg0: number, arg1: number) => any; }) => {
            return follower.pos(x, y);
        }, this);
    };
}










//-----------------------------------------------------------------------------
// Game_Vehicle
//
// The game object class for a vehicle.

 class Game_Vehicle extends Game_Character {
    //bgm: RPGMakerMV.AudioObject;
    constructor(...args:any){
        super();
        this.initialize.apply(this, ...args);
    }
    initialize(type?:any): void {
        Game_Character.prototype.initialize.call(this);
        this._type = type;
        this.resetDirection();
        this.initMoveSpeed();
        this.loadSystemSettings();
    };

    initMembers(): void {
        Game_Character.prototype.initMembers.call(this);
        this._type = '';
        this._mapId = 0;
        this._altitude = 0;
        this._driving = false;
        this._bgm = null;
    };

    _type: string;
    _mapId: number;
    _altitude: number;
    _driving: boolean;
    _bgm: RPGMakerMV.AudioObject;

    isBoat(): boolean {
        return this._type === 'boat';
    };
    isShip(): boolean {
        return this._type === 'ship';
    };
    isAirship(): boolean {
        return this._type === 'airship';
    };
    resetDirection(): void {
        this.setDirection(4);
    };
    initMoveSpeed(): void {
        if (this.isBoat()) {
            this.setMoveSpeed(4);
        } else if (this.isShip()) {
            this.setMoveSpeed(5);
        } else if (this.isAirship()) {
            this.setMoveSpeed(6);
        }
    };
    vehicle(): any|Game_Vehicle {
        if (this.isBoat()) {
            return $dataSystem.boat;
        } else if (this.isShip()) {
            return $dataSystem.ship;
        } else if (this.isAirship()) {
            return $dataSystem.airship;
        } else {
            return null;
        }
    };


    /*loadSystemSettings(): void {
        let vehicle = this.vehicle();
        this._mapId = vehicle.startMapId;
        this.setPosition(vehicle.startX, vehicle.startY);
        this.setImage(vehicle.characterName, vehicle.characterIndex);
    };*/


    public loadSystemSettings() {
        let vehicle:any = this.vehicle();
        this._mapId = vehicle.startMapId;
        this.setPosition(vehicle.startX, vehicle.startY);
        this.setImage(vehicle.characterName, vehicle.characterIndex);
    }

    refresh(): void {
        if (this._driving) {
            this._mapId = $gameMap.mapId();
            this.syncWithPlayer();
        } else if (this._mapId === $gameMap.mapId()) {
            this.locate(this.x, this.y);
        }
        if (this.isAirship()) {
            this.setPriorityType(this._driving ? 2 : 0);
        } else {
            this.setPriorityType(1);
        }
        this.setWalkAnime(this._driving);
        this.setStepAnime(this._driving);
        this.setTransparent(this._mapId !== $gameMap.mapId());
    };
    setLocation(mapId: number, x: number, y: number): void {
        this._mapId = mapId;
        this.setPosition(x, y);
        this.refresh();
    };
    pos(x: number, y: number): boolean {
        if (this._mapId === $gameMap.mapId()) {
            return Game_Character.prototype.pos.call(this, x, y);
        } else {
            return false;
        }
    };
    isMapPassable(x: number, y: number, d: number): boolean {
        var x2 = $gameMap.roundXWithDirection(x, d);
        var y2 = $gameMap.roundYWithDirection(y, d);
        if (this.isBoat()) {
            return $gameMap.isBoatPassable(x2, y2);
        } else if (this.isShip()) {
            return $gameMap.isShipPassable(x2, y2);
        } else if (this.isAirship()) {
            return true;
        } else {
            return false;
        }
    };
    getOn(): void {
        this._driving = true;
        this.setWalkAnime(true);
        this.setStepAnime(true);
        $gameSystem.saveWalkingBgm();
        this.playBgm();
    };
    getOff(): void {
        this._driving = false;
        this.setWalkAnime(false);
        this.setStepAnime(false);
        this.resetDirection();
        $gameSystem.replayWalkingBgm();
    };
    setBgm(bgm: RPGMakerMV.AudioObject): void {
        this._bgm = bgm;
    };
    playBgm(): void {
        AudioManager.playBgm(this._bgm || this.vehicle().bgm);
    };
    syncWithPlayer(): void {
        this.copyPosition($gamePlayer);
        this.refreshBushDepth();
    };
    screenY(): number {
        return Game_Character.prototype.screenY.call(this) - this._altitude;
    };
    shadowX(): number {
        return this.screenX();
    };
    shadowY(): number {
        return this.screenY() + this._altitude;
    };
    shadowOpacity(): number {
        return 255 * this._altitude / this.maxAltitude();
    };
    canMove(): boolean {
        if (this.isAirship()) {
            return this.isHighest();
        } else {
            return true;
        }
    };
    update(): void {
        Game_Character.prototype.update.call(this);
        if (this.isAirship()) {
            this.updateAirship();
        }
    };
    updateAirship(): void {
        this.updateAirshipAltitude();
        this.setStepAnime(this.isHighest());
        this.setPriorityType(this.isLowest() ? 0 : 2);
    };
    updateAirshipAltitude(): void {
        if (this._driving && !this.isHighest()) {
            this._altitude++;
        }
        if (!this._driving && !this.isLowest()) {
            this._altitude--;
        }
    };
    maxAltitude(): number {
        return 48;
    };
    isLowest(): boolean {
        return this._altitude <= 0;
    };
    isHighest(): boolean {
        return this._altitude >= this.maxAltitude();
    };
    isTakeoffOk(): boolean {
        return $gamePlayer.areFollowersGathered();
    };
    isLandOk(x: number, y: number, d: number): boolean {
        if (this.isAirship()) {
            if (!$gameMap.isAirshipLandOk(x, y)) {
                return false;
            }
            if ($gameMap.eventsXy(x, y).length > 0) {
                return false;
            }
        } else {
            var x2 = $gameMap.roundXWithDirection(x, d);
            var y2 = $gameMap.roundYWithDirection(y, d);
            if (!$gameMap.isValid(x2, y2)) {
                return false;
            }
            if (!$gameMap.isPassable(x2, y2, this.reverseDir(d))) {
                return false;
            }
            if (this.isCollidedWithCharacters(x2, y2)) {
                return false;
            }
        }
        return true;
    };
}













//-----------------------------------------------------------------------------
// Game_Event
//
// The game object class for an event. It contains functionality for event page
// switching and running parallel process events.

 class Game_Event extends Game_Character {
    //constructor(){}
    constructor(mapId?: number, eventId?: number){
        super();
        this.initialize.apply(this, arguments);
    }
    //initialize(): void{}
    initialize(mapId?: number, eventId?: number): void {
        Game_Character.prototype.initialize.call(this);
        this._mapId = mapId;
        this._eventId = eventId;
        this.locate(this.event().x, this.event().y);
        this.refresh();
    };
    _mapId: number;
    _eventId: number;
    initMembers(): void {
        Game_Character.prototype.initMembers.call(this);
        this._moveType = 0;
        this._trigger = 0;
        this._starting = false;
        this._erased = false;
        this._pageIndex = -2;
        this._originalPattern = 1;
        this._originalDirection = 2;
        this._prelockDirection = 0;
        this._locked = false;
    };
    _moveType: number;
    _trigger: number;
    _starting: boolean;
    _erased: boolean;
    _pageIndex: number;
    _originalPattern: number;
    _originalDirection: number;
    _prelockDirection: number;
    _locked: boolean;

    eventId(): number {
        return this._eventId;
    };
    event(): RPGMakerMV.MapEvent {
        return $dataMap.events[this._eventId];
    };
    page(): RPGMakerMV.MapEventPage {
        return this.event().pages[this._pageIndex];
    };
    list(): RPGMakerMV.EventCommand[] {
        return this.page().list;
    };
    isCollidedWithCharacters(x:number,y:number): boolean {
        return (Game_Character.prototype.isCollidedWithCharacters.call(this, x, y) ||
                this.isCollidedWithPlayerCharacters(x, y));
    };
    isCollidedWithEvents(x:number,y:number): boolean {
        var events = $gameMap.eventsXyNt(x, y);
        return events.length > 0;
    };
    isCollidedWithPlayerCharacters(x:number,y:number): boolean {
        return this.isNormalPriority() && $gamePlayer.isCollided(x, y);
    };
    lock(): void {
        if (!this._locked) {
            this._prelockDirection = this.direction();
            this.turnTowardPlayer();
            this._locked = true;
        }
    };
    unlock(): void {
        if (this._locked) {
            this._locked = false;
            this.setDirection(this._prelockDirection);
        }
    };
    updateStop(): void {
        if (this._locked) {
            this.resetStopCount();
        }
        Game_Character.prototype.updateStop.call(this);
        if (!this.isMoveRouteForcing()) {
            this.updateSelfMovement();
        }
    };
    updateSelfMovement(): void {
        if (!this._locked && this.isNearTheScreen() &&
                this.checkStop(this.stopCountThreshold())) {
            switch (this._moveType) {
            case 1:
                this.moveTypeRandom();
                break;
            case 2:
                this.moveTypeTowardPlayer();
                break;
            case 3:
                this.moveTypeCustom();
                break;
            }
        }
    };
    stopCountThreshold(): number {
        return 30 * (5 - this.moveFrequency());
    };
    moveTypeRandom(): void {
        switch (Math.randomInt(6)) {
        case 0: case 1:
            this.moveRandom();
            break;
        case 2: case 3: case 4:
            this.moveForward();
            break;
        case 5:
            this.resetStopCount();
            break;
        }
    };
    moveTypeTowardPlayer(): void {
        if (this.isNearThePlayer()) {
            switch (Math.randomInt(6)) {
            case 0: case 1: case 2: case 3:
                this.moveTowardPlayer();
                break;
            case 4:
                this.moveRandom();
                break;
            case 5:
                this.moveForward();
                break;
            }
        } else {
            this.moveRandom();
        }
    };
    isNearThePlayer(): boolean {
        var sx = Math.abs(this.deltaXFrom($gamePlayer.x));
        var sy = Math.abs(this.deltaYFrom($gamePlayer.y));
        return sx + sy < 20;
    };
    moveTypeCustom(): void {
        this.updateRoutineMove();
    };
    isStarting(): boolean {
        return this._starting;
    };
    clearStartingFlag(): void {
        this._starting = false;
    };
    isTriggerIn(triggers: number[]): boolean {
        return triggers.contains(this._trigger);
    };
    start(): void {
        var list = this.list();
        if (list && list.length > 1) {
            this._starting = true;
            if (this.isTriggerIn([0,1,2])) {
                this.lock();
            }
        }
    };
    erase(): void {
        this._erased = true;
        this.refresh();
    };
    refresh(): void {
        var newPageIndex = this._erased ? -1 : this.findProperPageIndex();
        if (this._pageIndex !== newPageIndex) {
            this._pageIndex = newPageIndex;
            this.setupPage();
        }
    };
    findProperPageIndex(): number {
        var pages = this.event().pages;
        for (var i = pages.length - 1; i >= 0; i--) {
            var page = pages[i];
            if (this.meetsConditions(page)) {
                return i;
            }
        }
        return -1;
    };
    meetsConditions(page: RPGMakerMV.MapEventPage): boolean {
        var c = page.conditions;
        if (c.switch1Valid) {
            if (!$gameSwitches.value(c.switch1Id)) {
                return false;
            }
        }
        if (c.switch2Valid) {
            if (!$gameSwitches.value(c.switch2Id)) {
                return false;
            }
        }
        if (c.variableValid) {
            if ($gameVariables.value(c.variableId) < c.variableValue) {
                return false;
            }
        }
        if (c.selfSwitchValid) {
            var key = [this._mapId, this._eventId, c.selfSwitchCh];
            if ($gameSelfSwitches.value(key) !== true) {
                return false;
            }
        }
        if (c.itemValid) {
            var item = $dataItems[c.itemId];
            if (!$gameParty.hasItem(item)) {
                return false;
            }
        }
        if (c.actorValid) {
            var actor = $gameActors.actor(c.actorId);
            if (!$gameParty.members().contains(actor)) {
                return false;
            }
        }
        return true;
    };
    setupPage(): void {
        if (this._pageIndex >= 0) {
            this.setupPageSettings();
        } else {
            this.clearPageSettings();
        }
        this.refreshBushDepth();
        this.clearStartingFlag();
        this.checkEventTriggerAuto();
    };
    clearPageSettings(): void {
        this.setImage('', 0);
        this._moveType = 0;
        this._trigger = null;
        this._interpreter = null;
        this.setThrough(true);
    };
    _interpreter: Game_Interpreter;
    setupPageSettings(): void {
        var page = this.page();
        var image = page.image;
        if (image.tileId > 0) {
            this.setTileImage(image.tileId);
        } else {
            this.setImage(image.characterName, image.characterIndex);
        }
        if (this._originalDirection !== image.direction) {
            this._originalDirection = image.direction;
            this._prelockDirection = 0;
            this.setDirectionFix(false);
            this.setDirection(image.direction);
        }
        if (this._originalPattern !== image.pattern) {
            this._originalPattern = image.pattern;
            this.setPattern(image.pattern);
        }
        this.setMoveSpeed(page.moveSpeed);
        this.setMoveFrequency(page.moveFrequency);
        this.setPriorityType(page.priorityType);
        this.setWalkAnime(page.walkAnime);
        this.setStepAnime(page.stepAnime);
        this.setDirectionFix(page.directionFix);
        this.setThrough(page.through);
        this.setMoveRoute(page.moveRoute);
        this._moveType = page.moveType;
        this._trigger = page.trigger;
        if (this._trigger === 4) {
            this._interpreter = new Game_Interpreter();
        } else {
            this._interpreter = null;
        }
    };
    isOriginalPattern(): boolean {
        return this.pattern() === this._originalPattern;
    };
    resetPattern(): void {
        this.setPattern(this._originalPattern);
    };
   
    checkEventTriggerTouch(x: number, y: number): boolean|any {
        if (!$gameMap.isEventRunning()) {
            if (this._trigger === 2 && $gamePlayer.pos(x, y)) {
                if (!this.isJumping() && this.isNormalPriority()) {
                    this.start();
                }
            }
        }
    };
    checkEventTriggerAuto(): void {
        if (this._trigger === 3) {
            this.start();
        }
    };
    update(): void {
        Game_Character.prototype.update.call(this);
        this.checkEventTriggerAuto();
        this.updateParallel();
    };
    updateParallel(): void {
        if (this._interpreter) {
            if (!this._interpreter.isRunning()) {
                this._interpreter.setup(this.list(), this._eventId);
            }
            this._interpreter.update();
        }
    };
    locate(x: number, y: number): void {
        Game_Character.prototype.locate.call(this, x, y);
        this._prelockDirection = 0;
    };
    forceMoveRoute(moveRoute: RPGMakerMV.MoveRoute): void {
        Game_Character.prototype.forceMoveRoute.call(this, moveRoute);
        this._prelockDirection = 0;
    };
    //getEventInfo(): RPGMakerMV.MapEventInfo{return null;}
}

//-----------------------------------------------------------------------------
// Game_Interpreter
//
// The interpreter for running event commands.

 class Game_Interpreter {
    _imageReservationId: any;
    constructor(depth?: number){
        this.initialize.apply(this, arguments);
    }
    initialize(depth?: number): void {
        this._depth = depth || 0;
        this.checkOverflow();
        this.clear();
        this._branch = {};
        this._params = [];
        this._indent = 0;
        this._frameCount = 0;
        this._freezeChecker = 0;
    };
    _depth: number;
    _branch: { [key: number]: number }|any;
    _params: any[]|any;
    _indent: number;
    _frameCount: number;
    _freezeChecker: number;
    checkOverflow(): void {
        if (this._depth >= 100) {
            throw new Error('Common event calls exceeded the limit');
        }
    };
    clear(): void {
        this._mapId = 0;
        this._eventId = 0;
        this._list = null;
        this._index = 0;
        this._waitCount = 0;
        this._waitMode = '';
        this._comments = '';
        this._character = null;
        this._childInterpreter = null;
    };
    _mapId: number;
    _eventId: number;
    _list: RPGMakerMV.EventCommand[];
    _index: number;
    _waitCount: number;
    _waitMode: string;
    _comments: string|any;
    _eventInfo: RPGMakerMV.EventInfo;
    _character: Game_Character;
    _childInterpreter: Game_Interpreter;

    setup(list: RPGMakerMV.EventCommand[]|RPGMakerMV.EventCommand|any, eventId?: number): void {
        this.clear();
        this._mapId = $gameMap.mapId();
        this._eventId = eventId || 0;
        this._list = list;
        Game_Interpreter.requestImages(list);
    };
    eventId(): number {
        return this._eventId;
    };
    isOnCurrentMap(): boolean {
        return this._mapId === $gameMap.mapId();
    };
   // setEventInfo(eventInfo: RPGMakerMV.EventInfo): boolean{return false;}
    setupReservedCommonEvent(): boolean {
        if ($gameTemp.isCommonEventReserved()) {
            this.setup($gameTemp.reservedCommonEvent().list);
            $gameTemp.clearCommonEvent();
            return true;
        } else {
            return false;
        }
    };
    isRunning(): boolean {
        return !!this._list;
    };
    update(): void {
        while (this.isRunning()) {
            if (this.updateChild() || this.updateWait()) {
                break;
            }
            if (SceneManager.isSceneChanging()) {
                break;
            }
            if (!this.executeCommand()) {
                break;
            }
            if (this.checkFreeze()) {
                break;
            }
        }
    };
    updateChild(): boolean {
        if (this._childInterpreter) {
            this._childInterpreter.update();
            if (this._childInterpreter.isRunning()) {
                return true;
            } else {
                this._childInterpreter = null;
            }
        }
        return false;
    };
    updateWait(): boolean {
        return this.updateWaitCount() || this.updateWaitMode();
    };
    updateWaitCount(): boolean {
        if (this._waitCount > 0) {
            this._waitCount--;
            return true;
        }
        return false;
    };
    updateWaitMode(): boolean {
        var waiting = false;
        switch (this._waitMode) {
        case 'message':
            waiting = $gameMessage.isBusy();
            break;
        case 'transfer':
            waiting = $gamePlayer.isTransferring();
            break;
        case 'scroll':
            waiting = $gameMap.isScrolling();
            break;
        case 'route':
            waiting = this._character.isMoveRouteForcing();
            break;
        case 'animation':
            waiting = this._character.isAnimationPlaying();
            break;
        case 'balloon':
            waiting = this._character.isBalloonPlaying();
            break;
        case 'gather':
            waiting = $gamePlayer.areFollowersGathering();
            break;
        case 'action':
            waiting = BattleManager.isActionForced();
            break;
        case 'video':
            waiting = Graphics.isVideoPlaying();
            break;
        case 'image':
            waiting = !ImageManager.isReady();
            break;
        }
        if (!waiting) {
            this._waitMode = '';
        }
        return waiting;
    };
    setWaitMode(waitMode: string): void {
        this._waitMode = waitMode;
    };
    wait(duration: number): void {
        this._waitCount = duration;
    };
    fadeSpeed(): number {
        return 24;
    };
    executeCommand(): boolean {
        var command = this.currentCommand();
        if (command) {
            this._params = command.parameters;
            this._indent = command.indent;
            let methodName = 'command' + command.code;
            if (typeof this[methodName] === 'function') {
                if (!this[methodName]()) {
                    return false;
                }
            }
            this._index++;
        } else {
            this.terminate();
        }
        return true;
    };
    checkFreeze(): boolean {
        if (this._frameCount !== Graphics.frameCount) {
            this._frameCount = Graphics.frameCount;
            this._freezeChecker = 0;
        }
        if (this._freezeChecker++ >= 100000) {
            return true;
        } else {
            return false;
        }
    };
    terminate(): void {
        this._list = null;
        this._comments = '';
    };
    skipBranch(): void {
        while (this._list[this._index + 1].indent > this._indent) {
            this._index++;
        }
    };
    currentCommand(): RPGMakerMV.EventCommand {
        return this._list[this._index];
    };
    nextEventCode(): number {
        var command = this._list[this._index + 1];
        if (command) {
            return command.code;
        } else {
            return 0;
        }
    };
    iterateActorId(param: number, callback: RPGMakerMV.ActorIteratorCallback|any): void {
        if (param === 0) {
            $gameParty.members().forEach(callback);
        } else {
            var actor = $gameActors.actor(param);
            if (actor) {
                callback(actor);
            }
        }
    };
    iterateActorEx(param1: number, param2: number, callback: RPGMakerMV.ActorIteratorCallback|any): void {
        if (param1 === 0) {
            this.iterateActorId(param2, callback);
        } else {
            this.iterateActorId($gameVariables.value(param2), callback);
        }
    };
    iterateActorIndex(param: number, callback: RPGMakerMV.ActorIteratorCallback|any): void {
        if (param < 0) {
            $gameParty.members().forEach(callback);
        } else {
            var actor = $gameParty.members()[param];
            if (actor) {
                callback(actor);
            }
        }
    };
    iterateEnemyIndex(param: number, callback: RPGMakerMV.EnemyIteratorCallback|any): void {
        if (param < 0) {
            $gameTroop.members().forEach(callback);
        } else {
            var enemy = $gameTroop.members()[param];
            if (enemy) {
                callback(enemy);
            }
        }
    };
    iterateBattler(param1: number, param2: number, callback: Function|any): void {
        if ($gameParty.inBattle()) {
            if (param1 === 0) {
                this.iterateEnemyIndex(param2, callback);
            } else {
                this.iterateActorId(param2, callback);
            }
        }
    };
    character(param: number): Game_Character {
        if ($gameParty.inBattle()) {
            return null;
        } else if (param < 0) {
            return $gamePlayer;
        } else if (this.isOnCurrentMap()) {
            return $gameMap.event(param > 0 ? param : this._eventId);
        } else {
            return null;
        }
    };
    operateValue(operation: number, operandType: number, operand: number): number {
        var value = operandType === 0 ? operand : $gameVariables.value(operand);
        return operation === 0 ? value : -value;
    };
    changeHp(target: Game_Battler|any, value: number, allowDeath: boolean): void {
        if (target.isAlive()) {
            if (!allowDeath && target.hp <= -value) {
                value = 1 - target.hp;
            }
            target.gainHp(value);
            if (target.isDead()) {
                target.performCollapse();
            }
        }
    };
    // Show Text
    command101(): boolean {
        if (!$gameMessage.isBusy()) {
            $gameMessage.setFaceImage(this._params[0], this._params[1]);
            $gameMessage.setBackground(this._params[2]);
            $gameMessage.setPositionType(this._params[3]);
            while (this.nextEventCode() === 401) {  // Text data
                this._index++;
                $gameMessage.add(this.currentCommand().parameters[0]);
            }
            switch (this.nextEventCode()) {
            case 102:  // Show Choices
                this._index++;
                this.setupChoices(this.currentCommand().parameters);
                break;
            case 103:  // Input Number
                this._index++;
                this.setupNumInput(this.currentCommand().parameters);
                break;
            case 104:  // Select Item
                this._index++;
                this.setupItemChoice(this.currentCommand().parameters);
                break;
            }
            this._index++;
            this.setWaitMode('message');
        }
        return false;
    };
    // Show Choices
    command102(): boolean {
        if (!$gameMessage.isBusy()) {
            this.setupChoices(this._params);
            this._index++;
            this.setWaitMode('message');
        }
        return false;
    };
    setupChoices(params: [string[], number, number?, number?, number?]): void {
        var choices:any = params[0].clone();
        var cancelType = params[1];
        var defaultType = params.length > 2 ? params[2] : 0;
        var positionType = params.length > 3 ? params[3] : 2;
        var background = params.length > 4 ? params[4] : 0;
        if (cancelType >= choices.length) {
            cancelType = -2;
        }
        $gameMessage.setChoices(choices, defaultType, cancelType);
        $gameMessage.setChoiceBackground(background);
        $gameMessage.setChoicePositionType(positionType);
        $gameMessage.setChoiceCallback((n: any) => {
            this._branch[this._indent] = n;
        });
    };
    // When [**]
    command402(): boolean {
        if (this._branch[this._indent] !== this._params[0]) {
            this.skipBranch();
        }
        return true;
    };
    // When Cancel
    command403(): boolean {
        if (this._branch[this._indent] >= 0) {
            this.skipBranch();
        }
        return true;
    };
    // Input Number
    command103(): boolean {
        if (!$gameMessage.isBusy()) {
            this.setupNumInput(this._params);
            this._index++;
            this.setWaitMode('message');
        }
        return false;
    };
    setupNumInput(params: [number, number]): void {
        $gameMessage.setNumberInput(params[0], params[1]);
    };
    // Select Item
    command104(): boolean {
        if (!$gameMessage.isBusy()) {
            this.setupItemChoice(this._params);
            this._index++;
            this.setWaitMode('message');
        }
        return false;
    };
    setupItemChoice(params: [number, number]): void {
        $gameMessage.setItemChoice(params[0], params[1] || 2);
    };
    // Show Scrolling Text
    command105(): boolean {
        if (!$gameMessage.isBusy()) {
            $gameMessage.setScroll(this._params[0], this._params[1]);
            while (this.nextEventCode() === 405) {
                this._index++;
                $gameMessage.add(this.currentCommand().parameters[0]);
            }
            this._index++;
            this.setWaitMode('message');
        }
        return false;
    };
    // Comment
    command108(): boolean {
        this._comments = [this._params[0]];
        while (this.nextEventCode() === 408) {
            this._index++;
            this._comments.push(this.currentCommand().parameters[0]);
        }
        return true;
    };
    // Conditional Branch
    command111(): boolean {
        var result = false;
        switch (this._params[0]) {
            case 0:  // Switch
                result = ($gameSwitches.value(this._params[1]) === (this._params[2] === 0));
                break;
            case 1:  // Variable
                var value1 = $gameVariables.value(this._params[1]);
                var value2;
                if (this._params[2] === 0) {
                    value2 = this._params[3];
                } else {
                    value2 = $gameVariables.value(this._params[3]);
                }
                switch (this._params[4]) {
                    case 0:  // Equal to
                        result = (value1 === value2);
                        break;
                    case 1:  // Greater than or Equal to
                        result = (value1 >= value2);
                        break;
                    case 2:  // Less than or Equal to
                        result = (value1 <= value2);
                        break;
                    case 3:  // Greater than
                        result = (value1 > value2);
                        break;
                    case 4:  // Less than
                        result = (value1 < value2);
                        break;
                    case 5:  // Not Equal to
                        result = (value1 !== value2);
                        break;
                }
                break;
            case 2:  // Self Switch
                if (this._eventId > 0) {
                    var key = [this._mapId, this._eventId, this._params[1]];
                    result = ($gameSelfSwitches.value(key) === (this._params[2] === 0));
                }
                break;
            case 3:  // Timer
                if ($gameTimer.isWorking()) {
                    if (this._params[2] === 0) {
                        result = ($gameTimer.seconds() >= this._params[1]);
                    } else {
                        result = ($gameTimer.seconds() <= this._params[1]);
                    }
                }
                break;
            case 4:  // Actor
                var actor = $gameActors.actor(this._params[1]);
                if (actor) {
                    var n = this._params[3];
                    switch (this._params[2]) {
                        case 0:  // In the Party
                            result = $gameParty.members().contains(actor);
                            break;
                        case 1:  // Name
                            result = (actor.name() === n);
                            break;
                        case 2:  // Class
                            result = actor.isClass($dataClasses[n]);
                            break;
                        case 3:  // Skill
                            result = actor.hasSkill(n);
                            break;
                        case 4:  // Weapon
                            result = actor.hasWeapon($dataWeapons[n]);
                            break;
                        case 5:  // Armor
                            result = actor.hasArmor($dataArmors[n]);
                            break;
                        case 6:  // State
                            result = actor.isStateAffected(n);
                            break;
                    }
                }
                break;
            case 5:  // Enemy
                var enemy = $gameTroop.members()[this._params[1]];
                if (enemy) {
                    switch (this._params[2]) {
                        case 0:  // Appeared
                            result = enemy.isAlive();
                            break;
                        case 1:  // State
                            result = enemy.isStateAffected(this._params[3]);
                            break;
                    }
                }
                break;
            case 6:  // Character
                var character = this.character(this._params[1]);
                if (character) {
                    result = (character.direction() === this._params[2]);
                }
                break;
            case 7:  // Gold
                switch (this._params[2]) {
                    case 0:  // Greater than or equal to
                        result = ($gameParty.gold() >= this._params[1]);
                        break;
                    case 1:  // Less than or equal to
                        result = ($gameParty.gold() <= this._params[1]);
                        break;
                    case 2:  // Less than
                        result = ($gameParty.gold() < this._params[1]);
                        break;
                }
                break;
            case 8:  // Item
                result = $gameParty.hasItem($dataItems[this._params[1]]);
                break;
            case 9:  // Weapon
                result = $gameParty.hasItem($dataWeapons[this._params[1]], this._params[2]);
                break;
            case 10:  // Armor
                result = $gameParty.hasItem($dataArmors[this._params[1]], this._params[2]);
                break;
            case 11:  // Button
                result = Input.isPressed(this._params[1]);
                break;
            case 12:  // Script
                result = !!eval(this._params[1]);
                break;
            case 13:  // Vehicle
                result = ($gamePlayer.vehicle() === $gameMap.vehicle(this._params[1]));
                break;
        }
        this._branch[this._indent] = result;
        if (this._branch[this._indent] === false) {
            this.skipBranch();
        }
        return true;
    };
    // Else
    command411(): boolean {
        if (this._branch[this._indent] !== false) {
            this.skipBranch();
        }
        return true;
    };
    // Loop
    command112(): boolean {
        return true;
    };
    // Repeat Above
    command413(): boolean {
        do {
            this._index--;
        } while (this.currentCommand().indent !== this._indent);
        return true;
    };
    // Break Loop
    command113(): boolean {
        var depth = 0;
        while (this._index < this._list.length - 1) {
            this._index++;
            var command = this.currentCommand();
    
            if (command.code === 112)
                depth++;
    
            if (command.code === 413) {
                if (depth > 0)
                    depth--;
                else
                    break;
            }
        }
        return true;
    };
    // Exit Event Processing
    command115(): boolean {
        this._index = this._list.length;
        return true;
    };
    // Common Event
    command117(): boolean {
        var commonEvent = $dataCommonEvents[this._params[0]];
        if (commonEvent) {
            var eventId = this.isOnCurrentMap() ? this._eventId : 0;
            this.setupChild(commonEvent.list, eventId);
        }
        return true;
    };
    setupChild(list: RPGMakerMV.EventCommand[], eventId: number): void {
        this._childInterpreter = new Game_Interpreter(this._depth + 1);
        this._childInterpreter.setup(list, eventId);
    };
    // Label
    command118(): boolean {
        return true;
    };
    // Jump to Label
    command119(): boolean {
        var labelName = this._params[0];
        for (var i = 0; i < this._list.length; i++) {
            var command = this._list[i];
            if (command.code === 118 && command.parameters[0] === labelName) {
                this.jumpTo(i);
                return;
            }
        }
        return true;
    };
    jumpTo(index: number): void {
        var lastIndex = this._index;
        var startIndex = Math.min(index, lastIndex);
        var endIndex = Math.max(index, lastIndex);
        var indent = this._indent;
        for (var i = startIndex; i <= endIndex; i++) {
            var newIndent = this._list[i].indent;
            if (newIndent !== indent) {
                this._branch[indent] = null;
                indent = newIndent;
            }
        }
        this._index = index;
    };
    // Control Switches
    command121(): boolean {
        for (var i = this._params[0]; i <= this._params[1]; i++) {
            $gameSwitches.setValue(i, this._params[2] === 0);
        }
        return true;
    };
    // Control Variables
    command122(): boolean {
        var value = 0;
        switch (this._params[3]) { // Operand
            case 0: // Constant
                value = this._params[4];
                break;
            case 1: // Variable
                value = $gameVariables.value(this._params[4]);
                break;
            case 2: // Random
                value = this._params[5] - this._params[4] + 1;
                for (var i = this._params[0]; i <= this._params[1]; i++) {
                    this.operateVariable(i, this._params[2], this._params[4] + Math.randomInt(value));
                }
                return true;
                break;
            case 3: // Game Data
                value = this.gameDataOperand(this._params[4], this._params[5], this._params[6]);
                break;
            case 4: // Script
                value = eval(this._params[4]);
                break;
        }
        for (var i = this._params[0]; i <= this._params[1]; i++) {
            this.operateVariable(i, this._params[2], value);
        }
        return true;
    };
    gameDataOperand(type: number, param1: number, param2: number): number {
        switch (type) {
        case 0:  // Item
            return $gameParty.numItems($dataItems[param1]);
        case 1:  // Weapon
            return $gameParty.numItems($dataWeapons[param1]);
        case 2:  // Armor
            return $gameParty.numItems($dataArmors[param1]);
        case 3:  // Actor
            var actor = $gameActors.actor(param1);
            if (actor) {
                switch (param2) {
                case 0:  // Level
                    return actor.level;
                case 1:  // EXP
                    return actor.currentExp();
                case 2:  // HP
                    return actor.hp;
                case 3:  // MP
                    return actor.mp;
                default:    // Parameter
                    if (param2 >= 4 && param2 <= 11) {
                        return actor.param(param2 - 4);
                    }
                }
            }
            break;
        case 4:  // Enemy
            var enemy = $gameTroop.members()[param1];
            if (enemy) {
                switch (param2) {
                case 0:  // HP
                    return enemy.hp;
                case 1:  // MP
                    return enemy.mp;
                default:    // Parameter
                    if (param2 >= 2 && param2 <= 9) {
                        return enemy.param(param2 - 2);
                    }
                }
            }
            break;
        case 5:  // Character
            var character = this.character(param1);
            if (character) {
                switch (param2) {
                case 0:  // Map X
                    return character.x;
                case 1:  // Map Y
                    return character.y;
                case 2:  // Direction
                    return character.direction();
                case 3:  // Screen X
                    return character.screenX();
                case 4:  // Screen Y
                    return character.screenY();
                }
            }
            break;
        case 6:  // Party
            actor = $gameParty.members()[param1];
            return actor ? actor.actorId() : 0;
        case 7:  // Other
            switch (param1) {
            case 0:  // Map ID
                return $gameMap.mapId();
            case 1:  // Party Members
                return $gameParty.size();
            case 2:  // Gold
                return $gameParty.gold();
            case 3:  // Steps
                return $gameParty.steps();
            case 4:  // Play Time
                return $gameSystem.playtime();
            case 5:  // Timer
                return $gameTimer.seconds();
            case 6:  // Save Count
                return $gameSystem.saveCount();
            case 7:  // Battle Count
                return $gameSystem.battleCount();
            case 8:  // Win Count
                return $gameSystem.winCount();
            case 9:  // Escape Count
                return $gameSystem.escapeCount();
            }
            break;
        }
        return 0;
    };
    operateVariable(variableId: number, operationType: number, value: number): void {
        try {
            var oldValue = $gameVariables.value(variableId);
            switch (operationType) {
            case 0:  // Set
                $gameVariables.setValue(variableId, oldValue = value);
                break;
            case 1:  // Add
                $gameVariables.setValue(variableId, oldValue + value);
                break;
            case 2:  // Sub
                $gameVariables.setValue(variableId, oldValue - value);
                break;
            case 3:  // Mul
                $gameVariables.setValue(variableId, oldValue * value);
                break;
            case 4:  // Div
                $gameVariables.setValue(variableId, oldValue / value);
                break;
            case 5:  // Mod
                $gameVariables.setValue(variableId, oldValue % value);
                break;
            }
        } catch (e) {
            $gameVariables.setValue(variableId, 0);
        }
    };
    // Control Self Switch
    command123(): boolean {
        if (this._eventId > 0) {
            var key = [this._mapId, this._eventId, this._params[0]];
            $gameSelfSwitches.setValue(key, this._params[1] === 0);
        }
        return true;
    };
    // Control Timer
    command124(): boolean {
        if (this._params[0] === 0) {  // Start
            $gameTimer.start(this._params[1] * 60);
        } else {  // Stop
            $gameTimer.stop();
        }
        return true;
    };
    // Change Gold
    command125(): boolean {
        var value = this.operateValue(this._params[0], this._params[1], this._params[2]);
        $gameParty.gainGold(value);
        return true;
    };
    // Change Items
    command126(): boolean {
        var value = this.operateValue(this._params[1], this._params[2], this._params[3]);
        $gameParty.gainItem($dataItems[this._params[0]], value);
        return true;
    };
    // Change Weapons
    command127(): boolean {
        var value = this.operateValue(this._params[1], this._params[2], this._params[3]);
        $gameParty.gainItem($dataWeapons[this._params[0]], value, this._params[4]);
        return true;
    };
    // Change Armors
    command128(): boolean {
        var value = this.operateValue(this._params[1], this._params[2], this._params[3]);
        $gameParty.gainItem($dataArmors[this._params[0]], value, this._params[4]);
        return true;
    };
    // Change Party Member
    command129(): boolean {
        var actor = $gameActors.actor(this._params[0]);
        if (actor) {
            if (this._params[1] === 0) {  // Add
                if (this._params[2]) {   // Initialize
                    $gameActors.actor(this._params[0]).setup(this._params[0]);
                }
                $gameParty.addActor(this._params[0]);
            } else {  // Remove
                $gameParty.removeActor(this._params[0]);
            }
        }
        return true;
    };
    // Change Battle BGM
    command132(): boolean {
        $gameSystem.setBattleBgm(this._params[0]);
        return true;
    };
    // Change Victory ME
    command133(): boolean {
        $gameSystem.setVictoryMe(this._params[0]);
        return true;
    };
    // Change Save Access
    command134(): boolean {
        if (this._params[0] === 0) {
            $gameSystem.disableSave();
        } else {
            $gameSystem.enableSave();
        }
        return true;
    };
    // Change Menu Access
    command135(): boolean {
        if (this._params[0] === 0) {
            $gameSystem.disableMenu();
        } else {
            $gameSystem.enableMenu();
        }
        return true;
    };
    // Change Encounter Disable
    command136(): boolean {
        if (this._params[0] === 0) {
            $gameSystem.disableEncounter();
        } else {
            $gameSystem.enableEncounter();
        }
        $gamePlayer.makeEncounterCount();
        return true;
    };
    // Change Formation Access
    command137(): boolean {
        if (this._params[0] === 0) {
            $gameSystem.disableFormation();
        } else {
            $gameSystem.enableFormation();
        }
        return true;
    };
    // Change Window Color
    command138(): boolean {
        $gameSystem.setWindowTone(this._params[0]);
        return true;
    };
    // Change Defeat ME
    command139(): boolean {
        $gameSystem.setDefeatMe(this._params[0]);
        return true;
    };
    // Change Vehicle BGM
    command140(): boolean {
        var vehicle = $gameMap.vehicle(this._params[0]);
        if (vehicle) {
            vehicle.setBgm(this._params[1]);
        }
        return true;
    };
    // Transfer Player
    command201(): boolean {
        if (!$gameParty.inBattle() && !$gameMessage.isBusy()) {
            var mapId, x, y;
            if (this._params[0] === 0) {  // Direct designation
                mapId = this._params[1];
                x = this._params[2];
                y = this._params[3];
            } else {  // Designation with variables
                mapId = $gameVariables.value(this._params[1]);
                x = $gameVariables.value(this._params[2]);
                y = $gameVariables.value(this._params[3]);
            }
            $gamePlayer.reserveTransfer(mapId, x, y, this._params[4], this._params[5]);
            this.setWaitMode('transfer');
            this._index++;
        }
        return false;
    };
    // Set Vehicle Location
    command202(): boolean {
        var mapId, x, y;
        if (this._params[1] === 0) {  // Direct designation
            mapId = this._params[2];
            x = this._params[3];
            y = this._params[4];
        } else {  // Designation with variables
            mapId = $gameVariables.value(this._params[2]);
            x = $gameVariables.value(this._params[3]);
            y = $gameVariables.value(this._params[4]);
        }
        var vehicle = $gameMap.vehicle(this._params[0]);
        if (vehicle) {
            vehicle.setLocation(mapId, x, y);
        }
        return true;
    };
    // Set Event Location
    command203(): boolean {
        var character = this.character(this._params[0]);
        if (character) {
            if (this._params[1] === 0) {  // Direct designation
                character.locate(this._params[2], this._params[3]);
            } else if (this._params[1] === 1) {  // Designation with variables
                var x = $gameVariables.value(this._params[2]);
                var y = $gameVariables.value(this._params[3]);
                character.locate(x, y);
            } else {  // Exchange with another event
                var character2 = this.character(this._params[2]);
                if (character2) {
                    character.swap(character2);
                }
            }
            if (this._params[4] > 0) {
                character.setDirection(this._params[4]);
            }
        }
        return true;
    };
    // Scroll Map
    command204(): boolean {
        if (!$gameParty.inBattle()) {
            if ($gameMap.isScrolling()) {
                this.setWaitMode('scroll');
                return false;
            }
            $gameMap.startScroll(this._params[0], this._params[1], this._params[2]);
        }
        return true;
    };
    // Set Movement Route
    command205(): boolean {
        $gameMap.refreshIfNeeded();
        this._character = this.character(this._params[0]);
        if (this._character) {
            this._character.forceMoveRoute(this._params[1]);
            if (this._params[1].wait) {
                this.setWaitMode('route');
            }
        }
        return true;
    };
    // Getting On and Off Vehicles
    command206(): boolean {
        $gamePlayer.getOnOffVehicle();
        return true;
    };
    // Change Transparency
    command211(): boolean {
        $gamePlayer.setTransparent(this._params[0] === 0);
        return true;
    };
    // Show Animation
    command212(): boolean {
        this._character = this.character(this._params[0]);
        if (this._character) {
            this._character.requestAnimation(this._params[1]);
            if (this._params[2]) {
                this.setWaitMode('animation');
            }
        }
        return true;
    };
    // Show Balloon Icon
    command213(): boolean {
        this._character = this.character(this._params[0]);
        if (this._character) {
            this._character.requestBalloon(this._params[1]);
            if (this._params[2]) {
                this.setWaitMode('balloon');
            }
        }
        return true;
    };
    // Erase Event
    command214(): boolean {
        if (this.isOnCurrentMap() && this._eventId > 0) {
            $gameMap.eraseEvent(this._eventId);
        }
        return true;
    };
    // Change Player Followers
    command216(): boolean {
        if (this._params[0] === 0) {
            $gamePlayer.showFollowers();
        } else {
            $gamePlayer.hideFollowers();
        }
        $gamePlayer.refresh();
        return true;
    };
    // Gather Followers
    command217(): boolean {
        if (!$gameParty.inBattle()) {
            $gamePlayer.gatherFollowers();
            this.setWaitMode('gather');
        }
        return true;
    };
    // Fadeout Screen
    command221(): boolean {
        if (!$gameMessage.isBusy()) {
            $gameScreen.startFadeOut(this.fadeSpeed());
            this.wait(this.fadeSpeed());
            this._index++;
        }
        return false;
    };
    // Fadein Screen
    command222(): boolean {
        if (!$gameMessage.isBusy()) {
            $gameScreen.startFadeIn(this.fadeSpeed());
            this.wait(this.fadeSpeed());
            this._index++;
        }
        return false;
    };
    // Tint Screen
    command223(): boolean {
        $gameScreen.startTint(this._params[0], this._params[1]);
        if (this._params[2]) {
            this.wait(this._params[1]);
        }
        return true;
    };
    // Flash Screen
    command224(): boolean {
        $gameScreen.startFlash(this._params[0], this._params[1]);
        if (this._params[2]) {
            this.wait(this._params[1]);
        }
        return true;
    };
    // Shake Screen
    command225(): boolean {
        $gameScreen.startShake(this._params[0], this._params[1], this._params[2]);
        if (this._params[3]) {
            this.wait(this._params[2]);
        }
        return true;
    };
    // Wait
    command230(): boolean {
        this.wait(this._params[0]);
        return true;
    };
    // Show Picture
    command231(): boolean {
        var x, y;
        if (this._params[3] === 0) {  // Direct designation
            x = this._params[4];
            y = this._params[5];
        } else {  // Designation with variables
            x = $gameVariables.value(this._params[4]);
            y = $gameVariables.value(this._params[5]);
        }
        $gameScreen.showPicture(this._params[0], this._params[1], this._params[2],
            x, y, this._params[6], this._params[7], this._params[8], this._params[9]);
        return true;
    };
    // Move Picture
    command232(): boolean {
        var x, y;
        if (this._params[3] === 0) {  // Direct designation
            x = this._params[4];
            y = this._params[5];
        } else {  // Designation with variables
            x = $gameVariables.value(this._params[4]);
            y = $gameVariables.value(this._params[5]);
        }
        $gameScreen.movePicture(this._params[0], this._params[2], x, y, this._params[6],
            this._params[7], this._params[8], this._params[9], this._params[10]);
        if (this._params[11]) {
            this.wait(this._params[10]);
        }
        return true;
    };
    // Rotate Picture
    command233(): boolean {
        $gameScreen.rotatePicture(this._params[0], this._params[1]);
        return true;
    };
    // Tint Picture
    command234(): boolean {
        $gameScreen.tintPicture(this._params[0], this._params[1], this._params[2]);
        if (this._params[3]) {
            this.wait(this._params[2]);
        }
        return true;
    };
    // Erase Picture
    command235(): boolean {
        $gameScreen.erasePicture(this._params[0]);
        return true;
    };
    // Set Weather Effect
    command236(): boolean {
        if (!$gameParty.inBattle()) {
            $gameScreen.changeWeather(this._params[0], this._params[1], this._params[2]);
            if (this._params[3]) {
                this.wait(this._params[2]);
            }
        }
        return true;
    };
    // Play BGM
    command241(): boolean {
        AudioManager.playBgm(this._params[0]);
        return true;
    };
    // Fadeout BGM
    command242(): boolean {
        AudioManager.fadeOutBgm(this._params[0]);
        return true;
    };
    // Save BGM
    command243(): boolean {
        $gameSystem.saveBgm();
        return true;
    };
    // Resume BGM
    command244(): boolean {
        $gameSystem.replayBgm();
        return true;
    };
    // Play BGS
    command245(): boolean {
        AudioManager.playBgs(this._params[0]);
        return true;
    };
    // Fadeout BGS
    command246(): boolean {
        AudioManager.fadeOutBgs(this._params[0]);
        return true;
    };
    // Play ME
    command249(): boolean {
        AudioManager.playMe(this._params[0]);
        return true;
    };
    // Play SE
    command250(): boolean {
        AudioManager.playSe(this._params[0]);
        return true;
    };
    // Stop SE
    command251(): boolean {
        AudioManager.stopSe();
        return true;
    };
    // Play Movie
    command261(): boolean {
        if (!$gameMessage.isBusy()) {
            var name = this._params[0];
            if (name.length > 0) {
                var ext = this.videoFileExt();
                Graphics.playVideo('movies/' + name + ext);
                this.setWaitMode('video');
            }
            this._index++;
        }
        return false;
    };
    videoFileExt(): string {
        if (Graphics.canPlayVideoType('video/webm') && !Utils.isMobileDevice()) {
            return '.webm';
        } else {
            return '.mp4';
        }
    };
    // Change Map Name Display
    command281(): boolean {
        if (this._params[0] === 0) {
            $gameMap.enableNameDisplay();
        } else {
            $gameMap.disableNameDisplay();
        }
        return true;
    };
    // Change Tileset
    command282(): boolean {
        var tileset = $dataTilesets[this._params[0]];
        if(!this._imageReservationId){
            this._imageReservationId = Utils.generateRuntimeId();
        }
    
        var allReady = tileset.tilesetNames.map(tilesetName => {
            return ImageManager.reserveTileset(tilesetName, 0, this._imageReservationId);
        }, this).every(function(bitmap) {return bitmap.isReady();});
    
        if (allReady) {
            $gameMap.changeTileset(this._params[0]);
            ImageManager.releaseReservation(this._imageReservationId);
            this._imageReservationId = null;
    
            return true;
        } else {
            return false;
        }
    };
    // Change Battle Back
    command283(): boolean {
        $gameMap.changeBattleback(this._params[0], this._params[1]);
        return true;
    };
    // Change Parallax
    command284(): boolean {
        $gameMap.changeParallax(this._params[0], this._params[1],
            this._params[2], this._params[3], this._params[4]);
        return true;
    };
    // Get Location Info
    command285(): boolean {
        var x, y, value;
        if (this._params[2] === 0) {  // Direct designation
            x = this._params[3];
            y = this._params[4];
        } else {  // Designation with variables
            x = $gameVariables.value(this._params[3]);
            y = $gameVariables.value(this._params[4]);
        }
        switch (this._params[1]) {
        case 0:     // Terrain Tag
            value = $gameMap.terrainTag(x, y);
            break;
        case 1:     // Event ID
            value = $gameMap.eventIdXy(x, y);
            break;
        case 2:     // Tile ID (Layer 1)
        case 3:     // Tile ID (Layer 2)
        case 4:     // Tile ID (Layer 3)
        case 5:     // Tile ID (Layer 4)
            value = $gameMap.tileId(x, y, this._params[1] - 2);
            break;
        default:    // Region ID
            value = $gameMap.regionId(x, y);
            break;
        }
        $gameVariables.setValue(this._params[0], value);
        return true;
    };
    // Battle Processing
    command301(): boolean {
        if (!$gameParty.inBattle()) {
            var troopId;
            if (this._params[0] === 0) {  // Direct designation
                troopId = this._params[1];
            } else if (this._params[0] === 1) {  // Designation with a variable
                troopId = $gameVariables.value(this._params[1]);
            } else {  // Same as Random Encounter
                troopId = $gamePlayer.makeEncounterTroopId();
            }
            if ($dataTroops[troopId]) {
                BattleManager.setup(troopId, this._params[2], this._params[3]);
                BattleManager.setEventCallback((n: any) => {
                    this._branch[this._indent] = n;
                });
                $gamePlayer.makeEncounterCount();
                SceneManager.push(Scene_Battle);
            }
        }
        return true;
    };
    // If Win
    command601(): boolean {
        if (this._branch[this._indent] !== 0) {
            this.skipBranch();
        }
        return true;
    };
    // If Escape
    command602(): boolean {
        if (this._branch[this._indent] !== 1) {
            this.skipBranch();
        }
        return true;
    };
    // If Lose
    command603(): boolean {
        if (this._branch[this._indent] !== 2) {
            this.skipBranch();
        }
        return true;
    };
    // Shop Processing
    command302(): boolean {
        if (!$gameParty.inBattle()) {
            var goods = [this._params];
            while (this.nextEventCode() === 605) {
                this._index++;
                goods.push(this.currentCommand().parameters);
            }
            SceneManager.push(Scene_Shop);
            SceneManager.prepareNextScene(goods, this._params[4]);
        }
        return true;
    };
    // Name Input Processing
    command303(): boolean {
        if (!$gameParty.inBattle()) {
            if ($dataActors[this._params[0]]) {
                SceneManager.push(Scene_Name);
                SceneManager.prepareNextScene(this._params[0], this._params[1]);
            }
        }
        return true;
    };
    // Change HP
    command311(): boolean {
        var value = this.operateValue(this._params[2], this._params[3], this._params[4]);
        this.iterateActorEx(this._params[0], this._params[1], (actor: any) => {
            this.changeHp(actor, value, this._params[5]);
        });
        return true;
    };
    // Change MP
    command312(): boolean {
        var value = this.operateValue(this._params[2], this._params[3], this._params[4]);
        this.iterateActorEx(this._params[0], this._params[1], (actor: { gainMp: (arg0: number) => void; }) => {
            actor.gainMp(value);
        });
        return true;
    };
    // Change TP
    command326(): boolean {
        var value = this.operateValue(this._params[2], this._params[3], this._params[4]);
        this.iterateActorEx(this._params[0], this._params[1], (actor: { gainTp: (arg0: number) => void; }) => {
            actor.gainTp(value);
        });
        return true;
    };
    // Change State
    command313(): boolean {
        this.iterateActorEx(this._params[0], this._params[1], (actor: { isDead: () => any; addState: (arg0: any) => void; removeState: (arg0: any) => void; performCollapse: () => void; clearResult: () => void; }) => {
            var alreadyDead = actor.isDead();
            if (this._params[2] === 0) {
                actor.addState(this._params[3]);
            } else {
                actor.removeState(this._params[3]);
            }
            if (actor.isDead() && !alreadyDead) {
                actor.performCollapse();
            }
            actor.clearResult();
        });
        return true;
    };
    // Recover All
    command314(): boolean {
        this.iterateActorEx(this._params[0], this._params[1], (actor: { recoverAll: () => void; }) => {
            actor.recoverAll();
        });
        return true;
    };
    // Change EXP
    command315(): boolean {
        var value = this.operateValue(this._params[2], this._params[3], this._params[4]);
        this.iterateActorEx(this._params[0], this._params[1], (actor: { changeExp: (arg0: any, arg1: any) => void; currentExp: () => number; }) => {
            actor.changeExp(actor.currentExp() + value, this._params[5]);
        });
        return true;
    };
    // Change Level
    command316(): boolean {
        var value = this.operateValue(this._params[2], this._params[3], this._params[4]);
        this.iterateActorEx(this._params[0], this._params[1], (actor: { changeLevel: (arg0: any, arg1: any) => void; level: number; }) => {
            actor.changeLevel(actor.level + value, this._params[5]);
        });
        return true;
    };
    // Change Parameter
    command317(): boolean {
        var value = this.operateValue(this._params[3], this._params[4], this._params[5]);
        this.iterateActorEx(this._params[0], this._params[1], (actor: { addParam: (arg0: any, arg1: number) => void; }) => {
            actor.addParam(this._params[2], value);
        });
        return true;
    };
    // Change Skill
    command318(): boolean {
        this.iterateActorEx(this._params[0], this._params[1], (actor: { learnSkill: (arg0: any) => void; forgetSkill: (arg0: any) => void; }) => {
            if (this._params[2] === 0) {
                actor.learnSkill(this._params[3]);
            } else {
                actor.forgetSkill(this._params[3]);
            }
        });
        return true;
    };
    // Change Equipment
    command319(): boolean {
        var actor = $gameActors.actor(this._params[0]);
        if (actor) {
            actor.changeEquipById(this._params[1], this._params[2]);
        }
        return true;
    };
    // Change Name
    command320(): boolean {
        var actor = $gameActors.actor(this._params[0]);
        if (actor) {
            actor.setName(this._params[1]);
        }
        return true;
    };
    // Change Class
    command321(): boolean {
        var actor = $gameActors.actor(this._params[0]);
        if (actor && $dataClasses[this._params[1]]) {
            actor.changeClass(this._params[1], this._params[2]);
        }
        return true;
    };
    // Change Actor Images
    command322(): boolean {
        var actor = $gameActors.actor(this._params[0]);
        if (actor) {
            actor.setCharacterImage(this._params[1], this._params[2]);
            actor.setFaceImage(this._params[3], this._params[4]);
            actor.setBattlerImage(this._params[5]);
        }
        $gamePlayer.refresh();
        return true;
    };
    // Change Vehicle Image
    command323(): boolean {
        var vehicle = $gameMap.vehicle(this._params[0]);
        if (vehicle) {
            vehicle.setImage(this._params[1], this._params[2]);
        }
        return true;
    };
    // Change Nickname
    command324(): boolean {
        var actor = $gameActors.actor(this._params[0]);
        if (actor) {
            actor.setNickname(this._params[1]);
        }
        return true;
    };
    // Change Profile
    command325(): boolean {
        var actor = $gameActors.actor(this._params[0]);
        if (actor) {
            actor.setProfile(this._params[1]);
        }
        return true;
    };
    // Change Enemy HP
    command331(): boolean {
        var value = this.operateValue(this._params[1], this._params[2], this._params[3]);
        this.iterateEnemyIndex(this._params[0], (enemy:any) => {
            this.changeHp(enemy, value, this._params[4]);
        });
        return true;
    };
    // Change Enemy MP
    command332(): boolean {
        var value = this.operateValue(this._params[1], this._params[2], this._params[3]);
        this.iterateEnemyIndex(this._params[0], (enemy:any) => {
            enemy.gainMp(value);
        });
        return true;
    };
    // Change Enemy TP
    command342(): boolean {
        var value = this.operateValue(this._params[1], this._params[2], this._params[3]);
        this.iterateEnemyIndex(this._params[0], (enemy:any) => {
            enemy.gainTp(value);
        });
        return true;
    };
    // Change Enemy Stat{}
    command333(): boolean {
        this.iterateEnemyIndex(this._params[0], (enemy: { isDead: () => any; addState: (arg0: any) => void; removeState: (arg0: any) => void; performCollapse: () => void; clearResult: () => void; }) => {
            var alreadyDead = enemy.isDead();
            if (this._params[1] === 0) {
                enemy.addState(this._params[2]);
            } else {
                enemy.removeState(this._params[2]);
            }
            if (enemy.isDead() && !alreadyDead) {
                enemy.performCollapse();
            }
            enemy.clearResult();
        });
        return true;
    };
    // Enemy Recover All
    command334(): boolean {
        this.iterateEnemyIndex(this._params[0], (enemy:any) => {
            enemy.recoverAll();
        });
        return true;
    };
    // Enemy Appear
    command335(): boolean {
        this.iterateEnemyIndex(this._params[0], (enemy:any) => {
            enemy.appear();
            $gameTroop.makeUniqueNames();
        });
        return true;
    };
    // Enemy Transform
    command336(): boolean {
        this.iterateEnemyIndex(this._params[0], (enemy:any) => {
            enemy.transform(this._params[1]);
            $gameTroop.makeUniqueNames();
        });
        return true;
    };
    // Show Battle Animation
    command337(): boolean {
        if (this._params[2] == true) {
            this.iterateEnemyIndex(-1, (enemy:any) => {
                if (enemy.isAlive()) {
                    enemy.startAnimation(this._params[1],false,0);
                }
            });
        } else {
            this.iterateEnemyIndex(this._params[0], (enemy:any) => {
                if (enemy.isAlive()) {
                    enemy.startAnimation(this._params[1], false, 0);
                }
            });
        }
        return true;
    };
    // Force Action
    command339(): boolean {
        this.iterateBattler(this._params[0], this._params[1], (battler:any) => {
            if (!battler.isDeathStateAffected()) {
                battler.forceAction(this._params[2], this._params[3]);
                BattleManager.forceAction(battler);
                this.setWaitMode('action');
            }
        });
        return true;
    };
    // Abort Battle
    command340(): boolean {
        BattleManager.abort();
        return true;
    };
    // Open Menu Screen
    command351(): boolean {
        if (!$gameParty.inBattle()) {
            SceneManager.push(Scene_Menu);
            Window_MenuCommand.initCommandPosition();
        }
        return true;
    };
    // Open Save Screen
    command352(): boolean {
        if (!$gameParty.inBattle()) {
            SceneManager.push(Scene_Save);
        }
        return true;
    };
    // Game Over
    command353(): boolean {
        SceneManager.goto(Scene_Gameover);
        return true;
    };
    // Return to Title Screen
    command354(): boolean {
        SceneManager.goto(Scene_Title);
        return true;
    };
    // Script
    command355(): boolean {
        var script = this.currentCommand().parameters[0] + '\n';
        while (this.nextEventCode() === 655) {
            this._index++;
            script += this.currentCommand().parameters[0] + '\n';
        }
        eval(script);
        return true;
    };
    // Plugin Command
    command356(): boolean {
        var args = this._params[0].split(" ");
        var command = args.shift();
        this.pluginCommand(command, args);
        return true;
    };
    pluginCommand(command: string, args: string[]): void {
        // to be overridden by plugins
    };
    static requestImages(list: RPGMakerMV.EventCommand[], commonList?: number[]): void{
        if(!list) return;
    
        list.forEach(function(command){
            var params:any = command.parameters;
            switch(command.code){
                // Show Text
                case 101:
                    ImageManager.requestFace(params[0]);
                    break;
    
                // Common Event
                case 117:
                    var commonEvent = $dataCommonEvents[params[0]];
                    if (commonEvent) {
                        if (!commonList) {
                            commonList = [];
                        }
                        if (!commonList.contains(params[0])) {
                            commonList.push(params[0]);
                            Game_Interpreter.requestImages(commonEvent.list, commonList);
                        }
                    }
                    break;
    
                // Change Party Member
                case 129:
                    var actor = $gameActors.actor(params[0]);
                    if (actor && params[1] === 0) {
                        var name = actor.characterName();
                        ImageManager.requestCharacter(name);
                    }
                    break;
    
                // Set Movement Route
                case 205:
                    if(params[1]){
                        params[1].list.forEach((command:any) => {
                            var params = command.parameters;
                            if(command.code === Game_Character.ROUTE_CHANGE_IMAGE){
                                ImageManager.requestCharacter(params[0]);
                            }
                        });
                    }
                    break;
    
                // Show Animation, Show Battle Animation
                case 212: case 337:
                    if(params[1]) {
                        var animation = $dataAnimations[params[1]];
                        var name1 = animation.animation1Name;
                        var name2 = animation.animation2Name;
                        var hue1 = animation.animation1Hue;
                        var hue2 = animation.animation2Hue;
                        ImageManager.requestAnimation(name1, hue1);
                        ImageManager.requestAnimation(name2, hue2);
                    }
                    break;
    
                // Change Player Followers
                case 216:
                    if (params[0] === 0) {
                        $gamePlayer.followers().forEach((follower:any) => {
                            let name:any = follower.characterName();
                            ImageManager.requestCharacter(name);
                        });
                    }
                    break;
    
                // Show Picture
                case 231:
                    ImageManager.requestPicture(params[1]);
                    break;
    
                // Change Tileset
                case 282:
                    var tileset = $dataTilesets[params[0]];
                    tileset.tilesetNames.forEach( tilesetName => {
                        ImageManager.requestTileset(tilesetName);
                    });
                    break;
    
                // Change Battle Back
                case 283:
                    if ($gameParty.inBattle()) {
                        ImageManager.requestBattleback1(params[0]);
                        ImageManager.requestBattleback2(params[1]);
                    }
                    break;
    
                // Change Parallax
                case 284:
                    if (!$gameParty.inBattle()) {
                        ImageManager.requestParallax(params[0]);
                    }
                    break;
    
                // Change Actor Images
                case 322:
                    ImageManager.requestCharacter(params[1]);
                    ImageManager.requestFace(params[3]);
                    ImageManager.requestSvActor(params[5]);
                    break;
    
                // Change Vehicle Image
                case 323:
                    var vehicle = $gameMap.vehicle(params[0]);
                    if(vehicle){
                        ImageManager.requestCharacter(params[1]);
                    }
                    break;
    
                // Enemy Transform
                case 336:
                    var enemy = $dataEnemies[params[1]];
                    var name = enemy.battlerName;
                    var hue = enemy.battlerHue;
                    if ($gameSystem.isSideView()) {
                        ImageManager.requestSvEnemy(name, hue);
                    } else {
                        ImageManager.requestEnemy(name, hue);
                    }
                    break;
            }
        });
    };
}
  

  
